最近在学习 redux-saga, 由于 redux-saga 需要使用 Generator 函数, 所以下来就回顾了一下 Generator
Generator 函数是 ES6 提供的一种异步编程解决方案, 语法行为与传统函数完全不同
Generator 函数与普通函数没什么区别, 只是在 function 关键字后面多了一个 * 号, 函数内部多了一个 yield 关键字
- function* demo() {
- console.log(1)
- yield 111
- console.log(2)
- yield 222
- console.log(3)
- return 333
- }
上面的函数即为一个 Generator 函数, Generator 调用后并不会直接执行, 而是返回一个指向内部状态的指针对象需要调用该指针对象的 next 方法才会向下执行, 当遇到 yield 关键字的时候, 函数会挂起, 交给外部, 直到遇到下一次调用 next 方法
let g = demo()
此时若我们第一次调用
- let val1 = g.next()
- // 打印 1,val1 = {
- value: 111, done: false
- }
- let val2 = g.next()
- // 打印 2,val2 = {
- value: 222, done: false
- }
- let val3 = g.next()
- // 打印 3,val3 = {
- value: 333, done: true
- }
根据结果我们可以很清楚的看到当返回值的 done 为 true 的时候就代表 Generator 执行完毕, 此外 Generator 函数还可以被循环
- for (let val of demo()) {
- console.log(val)
- }
- // val 依次会打印出 111,222, 注意当 done 为 true 的时候不会打印 value 的值
当然 Generator 在工作中最常用到的就是处理异步函数, 下面举个例子:
- function demo(a, b) {
- return new Promise((resolve, reject) => {
- setTimeout(() => {
- resolve(a + b)
- }, 1000)
- })
- }
- function* gen(val) {
- let a = yield demo(1, 2)
- console.log(a)
- let b = yield '123'
- return b
- }
这里需要注意的是, 变量 a 的值是需要 next 方法传入的
- let g = gen()
- let {
- value
- } = g.next()
此时函数中的变量 a 的值就是再次调用 next 传入的值, 比如 g.next(value), 则此时 a 的值就是一个 Promise 的实例, 显然这不是我们想要的, 我们期望拿到的是 Promise.resolve 的值
那么根据上面的结果我们可以编写一个 Generator 执行器
- function execGen(gen) {
- let g = gen()
- function deep(val) {
- let {value, done} = g.next(val)
- if (done) {
- return
- }
- if (value instanceof Promise) {
- value.then(data => {
- deep(data)
- })
- } else {
- deep(value)
- }
- }
- deep()
- }
- execGen(gen)
- // gen 函数的 console 会正确的打印出值 3
其实如果不是 redux-saga 的话我感觉我工作中基本不会用到 Generator 函数, 个人感觉更优雅的是 async/await 来处理异步情况
- async function handler() {
- try{
- let val = await demo()
- }catch (e) {
- }
- }
最后还是期望有大佬能够帮忙指出相比于 async/await,Generator 有什么优势 ^_^
来源: https://www.cnblogs.com/songbw/p/11065561.html