一文了解你不知道的JavaScript生成器篇
简介
JavaScript的生成器(Generator)是ES6新引入的一个特性,可以使我们更加方便地控制异步代码流程,使代码更加简洁易懂。本文将介绍JavaScript生成器的基本语法、使用方法及示例,以帮助开发者快速掌握这一特性。
生成器语法
生成器语法使用function*定义一个生成器函数,通过yield表达式暂停和恢复代码执行状态。yield表达式可以返回值给调用方,同时也可以接收调用方传递过来的数据。示例代码如下:
function* myGenerator() {
yield 'hello';
yield 'world';
const value = yield 123;
console.log(value);
}
const gen = myGenerator();
console.log(gen.next()); // {value: "hello", done: false}
console.log(gen.next()); // {value: "world", done: false}
console.log(gen.next('abc')); // abc {value: 123, done: false}
console.log(gen.next()); // {value: undefined, done: true}
在上述代码中,myGenerator函数定义了一个生成器,通过yield表达式暂停执行并返回值。gen.next()方法将恢复执行并返回下一个值,如果生成器执行完毕则done属性为true。
生成器的使用
在实际开发中,生成器可以用于控制异步流程,比如一个异步任务的多步骤操作。示例代码如下:
function* fetchUser() {
const userId = yield fetch('/user/id');
const user = yield fetch(`/user/profile/${userId}`);
const followers = yield fetch(`/user/followers/${userId}`);
return {
user,
followers
};
}
function run(task) {
const gen = task();
function step(value) {
const result = gen.next(value);
if (result.done) {
return result.value;
} else {
return result.value.then(step);
}
}
return step();
}
run(fetchUser).then((data) => {
console.log(data);
});
在上述代码中,fetchUser生成器包含了一个异步的多步骤操作,通过yield表达式暂停和恢复代码执行,使用了Promise对异步操作进行处理。run函数用于启动生成器并控制异步流程,每一次异步操作结束后调用step函数进入下一个异步操作,直到代码执行完毕并返回最终结果。
示例说明
下面结合两个示例进一步说明生成器的使用方法和优势。
实现一个生成斐波那契数列的函数
function* fibonacci() {
let prev = 0;
let curr = 1;
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
const gen = fibonacci();
console.log(gen.next()); // {value: 1, done: false}
console.log(gen.next()); // {value: 1, done: false}
console.log(gen.next()); // {value: 2, done: false}
console.log(gen.next()); // {value: 3, done: false}
console.log(gen.next()); // {value: 5, done: false}
在上述代码中,fibonacci函数定义了一个斐波那契数列的生成器,实现了无限递推序列的计算,并通过yield表达式返回每一个数列的值。使用该生成器可以方便地生成斐波那契数列。
用生成器实现一个异步调度任务
function* taskQueue() {
const tasks = [];
let taskIndex = 0;
const runTask = function* (task) {
const result = yield task();
console.log(result);
if (taskIndex < tasks.length) {
yield* runTask(tasks[taskIndex++]);
}
};
while (true) {
const task = yield;
tasks.push(task);
if (taskIndex === 0) {
yield* runTask(tasks[taskIndex++]);
}
}
}
const queue = taskQueue();
queue.next();
queue.next(function* () {
return new Promise(resolve => {
setTimeout(() => {
resolve('task1 finished.');
queue.next();
}, 1000);
});
});
queue.next(function* () {
return new Promise(resolve => {
setTimeout(() => {
resolve('task2 finished.');
queue.next();
}, 2000);
});
});
queue.next(function* () {
return new Promise(resolve => {
setTimeout(() => {
resolve('task3 finished.');
queue.next();
}, 3000);
});
});
在上述代码中,taskQueue函数定义了一个异步任务调度器的生成器,该调度器支持通过yield表达式添加异步任务,并按照添加顺序依次执行。其中每一个异步任务通过Promise实现,使用yield表达式暂停执行状态,直到异步任务执行结束后继续执行下一步骤。
通过上述示例说明,我们可以看出生成器在异步流程控制方面的优势,使代码更加清晰易懂,同时也可以避免回调地狱的问题。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文了解你不知道的JavaScript生成器篇 - Python技术站