generator/thunk/async/await简单原理

众所周知:async+ await 就是 generator+自动执行器的语法糖
想要了解async/await就要先了解generator和thunk

generator

  1. 创建一个generator函数
//方法1
function* foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}
//方法2
function *foo(x) {
    yield x + 1;
    yield x + 2;
    return x + 3;
}
  1. generator函数的特点
    相比于普通函数,除了 return,还可以使用yield 返回多次

  2. 运行generator函数

//方法一:使用generator函数的next函数
const fn = foo(5) //创建了一个generator函数
fn.next()  //{value:6,done:false},调用next,直至遇见return,返回的yield语句后的值
...
fn.next() //{value: undefined, done:true}//

//方法2 使用for/of
for(let i of foo(5)){
   // console.log(i) //for of 遍历
}

插播for/of 和 for/in的区别

  • for in 适合对象(索引,不按顺序,遍历所有可枚举属性包括原型对象,包括数组上的方法)
  • for of 适合数组(值)
  1. next()函数
  • 第一个 next()用于启动生成器,传入参数无效,此时遇到 yield 就会暂停
  • 第 2 个 next()时,会启动第一个暂停的 yield,可以向其传递值,传递的值会替代第一个暂停的 yield 语句
    若不传递,就不会替代 yield 语句,就不会给左边赋值,左边就会时 undefined
function* foo(x) {
 let y =   yield x + 1;
    yield y+ 3;
    return x + y;
}
//正常
const fn = foo(2)
fn.next() // 3
fn.next(2) // 5
fn.next()  // 4

//异常
const fn = foo(2)
fn.next() // 3
fn.next() // y:undefined NaN
fn.next()  //  y:undefined NaN
  1. yield委托
  • 原因
    有时候需要将多个generator的值获取在一起,这时候就要使用yield* 委托到一个generator函数中
    yield* 后面跟一个生成器函数、或其他可迭代的对象(如一个数组、字符串、arguments对象)
  • 执行
function* g1(){
    yield 1
    yield 2
    return \'g1\'
}

function* g2(){
     yield 3
    yield 4
    return \'g2\'
}

function g(){
    yield* g1()
   let str =  yield* g2()
   console.log(str)
}

const gen = g()
gen.next() //{value:1,done:false}
gen.next() //{value:2,done:false}
gen.next() //{value:3,done:false}
gen.next() //{value:4,done:false}
gen.next() //{value:undefined,done:true}

**
为什么没有获取到g1和g2函数中return的值呢?
yield* 的作用是将函数本身的yield表达式代理出去。故在执行的时候只代理了yield表达式,没代理return语句。
yield* 返回的结果就是代理的函数return的结果。
**

thunk 函数

  1. 编译器中的thunk
  • 最初编译时出现了一个争论,即"求职策略”,
    比如函数传参数,是“按值传递”,传递时即执行完毕,传入的是一个具体的值;“按名传递",等到具体要使用的时候在执行求值。“按名传递"比按值传递多了一个优点,即若是传入的值没有使用,则可以节省效率。
    编译器中的 thunk,往往是将参数放入到一个临时函数中,在将函数传递整个函数题,这个临时函数就叫 thunk
  • js 中是按值传递的,js 中的 thunk 是用来处理多参数函数的,将多参数函数转变为参数为回调函数的单参数函数
  1. js中的thunk
如 readFile(‘/file.txt\',callback)//多参数函数
//thunk版本的
function myThunk(filename){
    return function (callback){
        func.readFile(\'/file.txt\',callback)
    }
}
const newFunc = myThunk(\'./file.txt\')
newFunc(callback)
  1. 实现简单的 thunk 转化器
//thunk转化器
function myThunk(fn){
return function (){
    let args = Array.prototype.slice.call(arguments)
    return function(callback){
        args.push(callback)
        return fn.apply(this,args)
    }
}
}
//转化readFile
var newRead = myThunk(readFile)
newRead(\'/file.txt\')(callback)
  1. thunk的作用
    thunk 可以用作 generator 的流程管理
//普通流程管理
cont readFile = thunkify(fs.readFile) //转化为thunk函数
function* gen(){
    let r1 = yield readFile(\'/file1.txt\')
    console.log(r1)
    let r2 = yield readFile(\'/file2.txt\')
    console.log(r2)
}
const fn = gen()
const result = fn.next()
result.value((err,data)=>{
    if(error) throw err
    const res  = fn.next(data)
    res.value((err,data)=>{
         if(error) throw err
    const res  = fn.next(data)
    })
})
//更强大的自动流程管理
const fn = (func)=>{
  var a = func()
  const next = (err,data)=>{
      if(err) throw err
      const r1 = a.next(data)
      if(r1.done){
          return r1.value
      }
      r1.value(next)
  }
  next()
}

自动流程管理和async/await的流程管理逻辑基本一致,主要async/await主要针对于promise

async/await

  1. 基本信息
  • async
    会返回一个 promise 对象,并且 promise 的状态是 fulfilled,promise 中的 resolve 的值是函数 return 的值
  • await
    会阻塞后端的代码,先执行外部的代码,
    await 后等一个 promise 会等 promise 状态变为 fulfilled 的,把 resolve 的结果 await 等待的结果
    若 promise 的状态变为 reject 会抛出异常 可以用 try catch 捕获
  1. async await 实现
//异步函数
function getNumber(d){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log(d)
            resolve(d)
        },10000)
    })
}
function asyncFn(func){
    const g = func()
   const next = (data)=>{
        const result = g.next(data);
        if(result.done){
          return result.value
        }
        else{
            result.value.then((sd,fd){
            next(sd)
           })
        }
   }
   next()
}
const func = function * (){
   const f1 = yield getNumber(1)
   const f2 = yield  getNumber(f1)
}
asyncFn(func);

参考文档

thunk 函数
async/await 简单实现

你可能感兴趣的:(菜鸡啄食——JS,javascript,前端,react.js,es6)