淘先锋技术网

首页 1 2 3 4 5 6 7

JavaScript Generator 是 ES6 新增的一种函数类型,它可以用来控制函数的执行,并允许动态地生成数据流。它最大的特点就是可以在函数执行过程中停下来,然后又从停止的地方继续执行,这也被称为“半暂停”。Generator 通常用于异步操作或数据流处理中,在异步代码中它可以让我们像同步代码一样编写程序。

Generator 函数使用一个特殊的语法来定义它的函数体,使用 function* 关键字定义,而不是普通函数的 function 关键字。如果函数需要返回值,我们可以使用 yield 返回,当我们调用 Generator 函数时,它不会立即执行,而是返回一个 Generator 对象,这个对象可以像迭代器一样通过 next() 方法控制函数的执行。执行到 yield 语句时,函数会暂停执行并将 yield 后的值作为返回值返回给调用者。当再次调用 next() 方法时,函数会从暂停的位置继续执行。

function* foo() {
console.log('foo1');
yield 1;
console.log('foo2');
yield 2;
console.log('foo3');
yield 3;
}
let gen = foo();
gen.next();  // =>'foo1', {value: 1, done: false}
gen.next();  // =>'foo2', {value: 2, done: false}
gen.next();  // =>'foo3', {value: 3, done: false}
gen.next();  // =>{value: undefined, done: true}

在上述代码中,我们通过 foo() 创建了一个 Generator 对象 gen,然后逐步通过 next() 暂停并执行函数体内部的代码。当执行到 yield 语句时,函数会暂停执行并将 yield 后的值返回给调用者,不过此时函数的执行并没有结束,它只是暂停执行了。最终当函数执行完毕时,它会返回 {value: undefined, done: true},done 值为 true 表示函数执行完成。如果在函数体内部调用 return 关键字,函数也会立即终止执行并返回值。

Generator 函数的另一个重要特性是可以在外部传入参数,将它们作为 yield 语句的返回值。

function* bar() {
let x = yield;
console.log(x);
return 'done';
}
let gen = bar();
gen.next();        //=>{value: undefined, done: false}
gen.next('hello'); //=>'hello', {value: 'done', done: true}

在上述代码中,我们通过 yield 暂停了函数 bar() 的执行,并将函数外部传入的值作为返回值返回了。这个特性可以将 Generator 函数和异步操作结合在一起使用,例如我们可以在执行异步操作时将它的回调函数作为参数传入,等异步操作完成时再通过回调函数将异步操作的结果传递回 Generator 函数内部。

Generator 最重要的应用之一就是异步操作的控制。例如当我们需要调用多个异步操作时,并在所有操作完成之后从最终结果中提取数据时,我们可以使用 Generator 函数来优雅地解决这个问题。

async function getAsyncData(url) {
const response = await fetch(url);
const result = await response.json();
return result;
}
function* fetchData() {
const users = yield getAsyncData('https://fake.com/users');
const posts = yield getAsyncData('https://fake.com/posts');
const comments = yield getAsyncData('https://fake.com/comments');
console.log(users, posts, comments);
}
const gen = fetchData();
let result = gen.next();
while(!result.done) {
result = gen.next(await result.value);
}
//=>[users], [comments], [posts]

在上述代码中,我们在 Generator 函数 fetchData() 中使用 yield 控制异步操作的执行流程。在调用 getAsyncData(url) 函数时,我们返回了一个 Promise 对象,Generator 函数暂停执行,等待 Promise 对象解析后再向下执行。在使用 while 循环不断调用 next() 方法的过程中,我们不断将上一次的 Promise 返回值作为参数传递给下一次 yield 语句,以此来控制整个异步操作的执行流程。

总之,JavaScript Generator 函数给我们的编程方式带来了很多的便利性。它可以帮助我们将异步操作和数据流控制使用同步方式编写,减少了回调函数的嵌套层次,增加代码的可读性和可维护性。它也适用于函数组合和迭代等场景,可以帮助我们更好地解决一些复杂的问题。