什么是 Generator 函数?
Generator 函数是 ES6 中引入的一种新的函数类型,通过特定的语法可以在函数执行过程中暂停并继续执行。相比于普通函数,Generator 函数具有以下几个特点:
- 函数执行过程中可以暂停并继续执行。
- 可以通过多次调用获取多个值,每次调用会返回一个迭代器对象(Iterator),通过该对象可以逐个获取函数执行过程中生成的值。
- 可以通过
yield
表达式生成值,也可以通过next()
方法获取值。 - 可以在函数内部捕获外部传入的异常,并进行处理。
ES7 在此基础上进一步完善了 Generator 函数的功能,并提供了更多的语法和方法。
ES7 中 Generator 函数的新特性
1. async
/await
ES7 中引入了 async
/await
语法,它们可以用来简化 Promise 的使用,并且在 Generator 函数中也有重要的应用。
async
和 await
分别是异步函数和异步操作的关键字,通过它们可以使异步代码具有同步的语法结构,可以更方便地处理异步操作。
举个栗子:
async function fetchData(url) { const response = await fetch(url); const json = await response.json(); return json; }
在 Generator 函数中,async
/await
语法可以替代 yield
关键字,代码的可读性和可维护性都得到了很大提升。例如:
// javascriptcn.com 代码示例 function *fetchData() { const response = yield fetch(url); const json = yield response.json(); return json; } (async () => { const generator = fetchData(); const response = await generator.next().value; const json = await generator.next(response).value; console.log(json); })();
上面这段代码可以被简化为:
// javascriptcn.com 代码示例 async function fetchData() { const response = await fetch(url); const json = await response.json(); return json; } (async () => { const json = await fetchData(); console.log(json); })();
以上代码说明:async
/await
语法可以使代码更加清晰、简洁、易读、易维护。
2. Generator.prototype.return()
Generator 函数可以接收一个参数作为完成整个迭代器的返回值,但是如果在遍历过程中提前终止或者要每次生成一个值来判断是否需要终止,则无法直接通过传入参数返回的方式实现。
为了解决这个问题,ES7 引入了 generator.prototype.return()
方法,可以用来在 Generator 函数的内部通过 yield
表达式生成的值来提前终止迭代器,并返回指定的值。
// javascriptcn.com 代码示例 function *generator() { yield 1; yield 2; return 3; } const result = Array.from(generator(), item => { if (item === 2) { generator.return(4); } return item; }); console.log(result); // [1, 4]
上面的代码中,当遍历到 2 时,我们提前调用了 generator.return(4)
,使得迭代器提前终止并返回指定的值 4。
3. Generator.prototype.throw()
Generator 函数中的错误处理可以通过 throw()
方法来实现,可以将错误从函数内部传递到函数外部进行处理。ES7 引入了 Generator.prototype.throw()
方法来实现这一点。
// javascriptcn.com 代码示例 function *generator() { try { const value = yield; console.log(value); } catch (error) { console.log('error', error); } } const g = generator(); g.next(); g.throw(new Error('test'));
上面代码中,在调用 next()
方法后会暂停执行,等待外部传入的值。当调用 throw()
方法时,会停止执行并跳转到函数 try-catch
块内部,输出错误。
Generator 函数实用场景
Generator 函数可以用于优化异步操作,将复杂的异步逻辑简化和拆分成多个小的任务进行处理,便于代码的阅读和维护,同时避免了回调地狱的问题。
下面是一个实用场景的例子:使用 Generator 函数实现异步流程控制。
// javascriptcn.com 代码示例 function *workflow() { const user = yield fetchData('/api/user'); const userId = user.id; const order = yield fetchData(`/api/order/${userId}`); const orderId = order.id; const detail = yield fetchData(`/api/detail/${orderId}`); return detail; } function run(generator) { const iterator = generator(); function handle(value) { const next = iterator.next(value); if (next.done) { return Promise.resolve(next.value); } return Promise.resolve(next.value) .then(handle) .catch(error => { return Promise.resolve(iterator.throw(error)) .then(handle); }); } return handle(); } run(workflow) .then(detail => console.log(detail)) .catch(error => console.log(error));
上述代码中,我们通过 run()
函数来启动 workflow()
函数执行流程,生成器 generator()
通过调用多个函数获取所有的数据并返回。
总结
Generator 函数通过提供暂停与恢复执行流的机制,允许我们将异步操作的多个步骤拆分成多个步骤进行处理,从而使代码具有同步的语法结构,并且减少了回调地狱的问题。
ES7 引入的新特性,如 async
/await
、Generator.prototype.return()
、Generator.prototype.throw()
等,使得 Generator 函数更加强大和实用,可以大大提高前端开发的效率和质量。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6541cc1e7d4982a6ebb6ab03