async,await,generator的使用和原理

async,await的使用和原理

1.使用

async function fn(){
    
    
    let p1 = await new Promise( (res,rej) =>{
    
    
        res(1111)
    })
    console.log(p1)
    let p2 = await new Promise( (res,rej) =>{
    
    
        res(2222)    // rej("错误")可以被返回的promise的catch捕获错误信息
    })
    console.log(p2)
   // let bb = await 222 // 被包装成 await Promise Promise.resolve(222)
   // console.log(aa)    // 可以被返回的promise的catch捕获语法错误信息
    return p1 + p2 // 被包装成promise Promise.resolve(1111)
}

 fn().then(data =>{
    
    
    console.log("data",data) // return 返回值 // 不是promise会被包装成promise
}).catch(err =>{
    
    
    console.log("err",err) 
})

2.特点

1.返回promise实例,可以捕获语法错误,捕获await后的失败的状态和结果
2.await 和 return 关键字后面的值 不是promise会被包装成promise Promise.resolve(value)

3.原理

问题 async中 await 等待效果是如何实现的 ,即看起来就是异步任务阻塞了后续同步代码的执行 ?
答 async 函数在编译后将代码以await进行了分割和分片 , 递归调用next方法,通过_context.next 来执行分割好的代码片段,下一次要执行的代码片段是在上一次的promise.then中执行的,所以代码执行必须promise状态改变后才行,所以会有异步阻塞的效果

以下是具体分析

  1. async await是 generator 和 co 的语法糖
  2. generator 返回一个迭代器对象含有next方法,next方法传递实参赋值给上一次yeild的返回值
  3. co 就是自动递归调用迭代器的next方法,并拿到value值,并在promise的then中递归调用
  4. async 实现了自己的co递归调用
    5. 最为关键的一点是 async 和 yeild在编译后将代码进行了分割(猜测根据ast语法树)
    分割点为await和yeild关键字,从而实现了代码的分片,分段执行

    6.通过_context.next指针来决定下一次执行哪一段代码
    7.以上流程可由下图简单表示
    在这里插入图片描述

a. generator 和 co (实现)的使用如下

 function* read(){
    
     
    let a = yield 'node'
    console.log(a)  // 222
    let b = yield new Promise( (res,rej)=>{
    
    
        res("vue")
    })             
    console.log(b)  // 333
    return a + b 
}

let it = read() // 返回迭代器对象

console.log(it.next(111)) //  {value: "node", done: false}
console.log(it.next(222)) //  {value: Promise实例, done: false}
console.log(it.next(333)) //  {value: 555, done: true}

// value 对应 yield关键字后面的值 
// next方法传递的实参会赋值给上一次yeild的返回值

// 实现简易co co就是自动递归调用迭代器的next方法,并拿到value值,并在promise的then中递归调用
function co(it){
    
    
    return new Promise( (res,rej) =>{
    
       
        function next(data){
    
    
          let {
    
    value,done} =  it.next(data)
          if(!done){
    
    
            // value如果不是promise将其包装成promise Promise.resolve(value)
            Promise.resolve(value).then(data =>{
    
    
                next(data)
            },rej)
          }else{
    
    
              return  res(value)
          }
        }
        next()
    })
}
co(read()).then(data =>{
    
    
    console.log(data)
})
  1. 将 async 函数放在babel中可得到编译后的代码,如下
// 自己实现regeneratorRuntime
let regeneratorRuntime = {
    
    
    mark(outerFn){
    
    
      return outerFn
    },
    wrap(innerFn,outerFn){
    
    
        const _context = {
    
    
            next : 0,
            done :false,
            abrupt(type,value){
    
    
                this.done = true
               return value
            },
            stop(){
    
    
                this.done = true
            }
        }
        return {
    
    
            next(data){
    
    
                _context.sent = data
                let value =  innerFn(_context)            
               return {
    
    
                   value,
                   done :_context.done
               }
            }
        }
    }
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
    
    
    try {
    
     var info = gen[key](arg); var value = info.value; } // gen.next()
    catch (error) {
    
    
        reject(error);
        return;
    }
    if (info.done) {
    
    
        resolve(value);
    }
    else {
    
    
        Promise.resolve(value).then(_next, _throw); // 递归调用_next,并传递了参数
    }
}
function _asyncToGenerator(fn) {
    
    
    return function () {
    
    
        var self = this, args = arguments;
        return new Promise(function (resolve, reject) {
    
    
            var gen = fn.apply(self, args); // 迭代器对象 {next:(){..}} // 
            function _next(value) {
    
    
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
            }
            function _throw(err) {
    
    
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
            }
            _next(undefined);
        });
    };
}
function fn() {
    
    
    return _fn.apply(this, arguments);
}
function _fn() {
    
    
    _fn = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
    
    
        var p1, p2;
        return regeneratorRuntime.wrap(function _callee$(_context) {
    
    
            while (1) {
    
    
                switch (_context.prev = _context.next) {
    
    
                    case 0:
                        _context.next = 2;
                        return new Promise(function (res, rej) {
    
    
                            res(1111);
                        });

                    case 2:
                        p1 = _context.sent;
                        console.log(p1);
                        _context.next = 6;
                        return new Promise(function (res, rej) {
    
    
                            res(2222); // rej("错误")可以被返回的promise的catch捕获错误信息
                        });

                    case 6:
                        p2 = _context.sent;
                        console.log(p2); // let bb = await 222 // 被包装成 await Promise Promise.resolve(222)
                        // console.log(aa)    // 可以被返回的promise的catch捕获语法错误信息

                        return _context.abrupt("return", p1 + p2);

                    case 9:
                    case "end":
                        return _context.stop();
                }
            }
        }, _callee);
    }));
    return _fn.apply(this, arguments);
}
fn().then(data =>{
    
    
    console.log(data) // 333 
})

猜你喜欢

转载自blog.csdn.net/qq_33418013/article/details/123241625