第三十章 async/await Promise同步异步

118 阅读4分钟

一、async/await:Promise+Generator的“语法糖”

1、async

作用:对函数的修饰
代码:async function xx(){ }

  • 让函数的返回值自动变为promise实例
    • 函数执行报错,则返回状态是rejected,值是报错原因的实例
    • 如果执行不报错,再看返回值
    • 返回值是新的实例,则以自己返回的promise实例为主
    • 其他情况:都返回一个状态是fulfilled,值是返回值的实例;函数没有返回值,则返回状态是fulfilled,值是undefined
    • 可以在函数中使用await

2、await

  • 作用:可以监听promise的实例状态,从而决定去做啥事 -> let xxx = await [promise实例];
  • 必须出现在一个经过async修饰的函数中
  • await后边需要跟一个promise实例【如果不是promise实例浏览器也会把其变为实例】
    await 14 => await Promise.resolve(14);
  • await会“等待”后边实例的状态为“成功”时,再把“当前上下位”中 await“下边”的代码执行! xxx就是实例状态为成功的返回结果
  • 如果await后边的实例状态是“失败”,则下边代码不会执行(控制台会爆红,但是不影响其他代码执行!!!)
  • 我们是基于try/catch实现对await后边实例为失败态的处理,避免爆红。
// 需求:设置三个定时器{2000,1000,3000},类似于ajax串行(第一个定时器触发后才能设置第二个...)

//回调地狱
setTimeout(() => {
    console.log('第一个定时器触发执行');
    setTimeout(() => {
        console.log('第二个定时器触发执行');
        setTimeout(() => {
            console.log('第三个定时器触发执行');
        }, 3000);
    }, 1000);
}, 2000); 

//async实现
const sleep = (interval = 1000) => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, interval);
    });
};
(async function(){
    await sleep(2000);
    console.log("第一个定时器触发执行");

    await sleep(1000);
    console.log('第二个定时器触发执行');

    await sleep(3000);
    console.log("第三个定时器触发执行");
    
})()

//以后写法
const handler = async () => {
    await sleep(2000);
    console.log('第一个定时器触发执行');

    await sleep(1000);
    console.log('第二个定时器触发执行');

    await sleep(3000);
    console.log('第三个定时器触发执行');
};
handler().then(() => {
    console.log('当函数内部所有await都处理完,而且对应的实例都是fulfilled,才会让handler执行的返回值是成功的promise实例!');
}).catch(() => {
    console.log('代码执行报错,或者其中某个await后面的实例是失败的,则直接让handler返回值也是失败的');
});

二、Promise & async/await 中的同步异步机制

1、同步

  • 在新建promise实例时executor函数的立即执行
new Promise(resolve=>{
    //executor函数会被立即执行【同步】:这里一般是管理异步编程代码,当异步结束,基于resolve/reject执行,控制实例状态的成功或者失败...
    console.log(1);
})
console.log(2); 
  • Promise.resolve()/reject() 执行时会立即修改实例状态和值
let p1 = new Promise(resolve=>{
    resolve(100);   //resolve/reject执行会立即修改实例状态和值【同步】
    // reject();
})
console.log(p1);    //fulfilled->100 
  • 遇到await
  • 把await后边的东西进行处理【同步】,获取一个promise实例\
  • 然后把当前上下文中,await下面的代码设置为“异步的微任务”\
  • 进入WebAPI中监听,当await后边的实例是成功的,再挪至EventQueue中排队等着

2、异步

  • then方法都是异步微任务
//执行THEN的时候,此时不知道p1实例的状态
//   + 把 onfulfilled & onrejected 存储到PROMISE内部的集合中
// p1.then(onfulfilled,onrejected)    【异步】
//     + 如果此时已知p1的实例状态(不是pending),会根据状态去执行onfulfilled/onrejected;
//         + 但并不会立即执行,而是创建一个“异步的微任务”
//         + 进入到WebAPI中去监听,但是此时已经知道状态是成功的,则直接再挪至EventQueue中去排队
//         + 当同步代码执行完,主线程空闲下来了,再去EventQueue中查找

p1.then(value=>{
    console.log('成功',value);
},reason=>{
    console.log('失败',reason);
});
console.log(111);
let p1 = new Promise(resolve => {
    setTimeout(() => {
        /!* 
        立即修改实例的状态和值「同步」
        通知之前在集合中存储的方法执行「异步微任务」
          + 把存储的方法扔到WebAPI中去监听,但是发现实例状态已经是成功了,则挪至到EventQueue中排队等着
          + 把此上下文中剩下的代码执行完,再去获取这个异步任务执行
        *!/
        resolve(100);
        console.log(222, p1);
    }, 2000);
});
// console.log(p1); //pending & undefined
/!*
 执行THEN的时候,此时不知道p1实例的状态
   + 把 onfulfilled & onrejected 存储到PROMISE内部的集合中
 *!/
p1.then(value => {
    console.log('成功:', value);
});
console.log(111);