美文网首页
async await实现原理

async await实现原理

作者: sun_hl | 来源:发表于2021-07-19 16:00 被阅读0次

详见链接:https://www.jianshu.com/p/79487965a0ca

Generator

  1. 调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。
  2. 以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。
  3. value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
    generator 函数的执行方法如下:
function* gen(x) {
  console.log('start')
  const y = yield x * 2
  return y
}

const g = gen(1)
g.next()   // start { value: 2, done: false }
g.next(4)  // { value: 4, done: true }
function* helloWorld () {
    yield 'hello'
    yield 'world'
    return 'ending'
}
 
var hw = helloWorld()
console.log(hw)         // helloWorld {<suspended>}
console.log(hw.next())  // {value: "hello", done: false}
console.log(hw.next())  // {value: "world", done: false}
console.log(hw.next())  // {value: "ending", done: false}
console.log(hw.next())  // {value: undefined, done: true}
  • gen() 不会立即执行,而是一上来就暂停,返回一个 Iterator 对象
  • 每次 g.next() 都会打破暂停状态去执行,直到遇到下一个 yield 或者 return
  • 遇到 yield 时,会执行 yeild 后面的表达式,并返回执行之后的值,然后再次进入暂停状态,此时 done: false。
  • next 函数可以接受参数,作为上个阶段异步任务的返回结果,被函数体内的变量接收
  • 遇到 return 时,会返回值,执行结束,即 done: true
  • 每次 g.next() 的返回值永远都是 {value: ... , done: ...} 的形式

async

https://www.jianshu.com/p/b4fd76c61dc9
async、await很好的解决了这一点,将异步强行转换为同步处理。
async函数会返回一个promise,并且Promise对象的状态值是resolved(成功的)
1、如果你没有在async函数中写return,那么Promise对象resolve的值就是是undefined
2、如果你写了return,那么return的值就会作为你成功的时候传入的值

await 等到之后,做了一件什么事情?
那么右侧表达式的结果,就是await要等的东西。
等到之后,对于await来说,分2个情况

  • 不是promise对象
  • 是promise对象

如果不是 promise , await会阻塞后面的代码,先执行async外面的同步代码,同步代码执行完,再回到async内部,把这个非promise的东西,作为 await表达式的结果。
如果它等到的是一个 promise 对象,await 也会暂停async后面的代码,先执行async外面的同步代码,等着 Promise 对象 fulfilled,然后把 resolve 的参数作为 await 表达式的运算结果。

  1. async其实就是对Generator的封装,只不过async可以自动执行next()。
  2. async必须等到里面所有的await执行完,async才开始return,返回的Promise状态才改变。除非遇到return和错误。
  3. async默认返回一个Promise,如果return不是一个Promise对象,就会被转为立即resolve的Promise,可以在then函数中获取返回值。
async function fn() {
    await console.log(1111111)
    await console.log(2222222)
    await console.log(3333333)
}
fn()
// 1111111
// 2222222
// 3333333
async function fn () {
    await 100
    await 200
    return 300
}
fn().then(res => {
    console.log(res) // 300
}) 

如果在async函数中抛出了错误,则终止错误结果,不会继续向下执行:

let data1 = new Promise((resove,reject) => {
    resolve('我是resolve成功的实例')
})
async function fn() {
    await data1
    throw new Error('我失败了')
    return data1
}
fn().then(res => console.log(res)).catch(res => console.log(res));
// Error:我失败了

如果希望一个await失败,后面的继续执行,可以使用try...catch或者在await后面的Promise跟一个catch方法:

async function f() {
  try {
    await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}
f().then(v => console.log(v))   // hello world
 

// catch
async function f() {
  await Promise.reject('出错了')
    .catch(e => console.log(e));   // 出错了
  return await Promise.resolve('hello world');
}
 
f().then(v => console.log(v))  // hello world

面试题

async function async1() {
    console.log("async1 start");
    await async2();
    console.log("async1 end");
    return 'async return';
}
 
async function async2() {
    console.log("async2");
}
 
console.log("script start");
 
setTimeout(function() {
    console.log("setTimeout");
}, 0);

async1().then(function (message) { console.log(message) });
 
new Promise(function(resolve) {
    console.log("promise1");
    resolve();
}).then(function() {
    console.log("promise2");
});
console.log("script end");
/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
async return
setTimeout
*/
async function async1(){
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}
async function async2(){ // 去掉了 async 关键字 返回结果相同
    console.log('async2')
}
console.log('script start')
setTimeout(function(){
    console.log('setTimeout')
},0)  
async1();
new Promise(function(resolve){
    console.log('promise1')
    resolve();
}).then(function(){
    console.log('promise2')
})
console.log('script end')
/*
script start
async1 start
async2
promise1
script end
async1 end
promise2
setTimeout
*/

需要说明的是:

正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。如果不是 Promise 对象,就直接返回对应的值(相当于直接Promise.resolve)。

async function f() {
  // 等同于
  // return 123;
  return await 123;
}

f().then(v => console.log(v))
// 123

其他面试题见以下链接
https://blog.csdn.net/wdhxs/article/details/110624773

相关文章

网友评论

      本文标题:async await实现原理

      本文链接:https://www.haomeiwen.com/subject/bpkmpltx.html