Await / Async 与 微任务 / 宏任务 原来是这样用的

375 阅读2分钟

Async 函数

  • 函数的返回值是Promise对象
  • Promise对象的结果由async函数执行的返回值决定
// 未加 async 之前
function fn(){
    return 1;
}

const result = fn();
console.log(result); // 1

// 加上 async 之后
function fn(){
    return 1;
}

const result = fn();
console.log(result);
 
输出结果为 Promise 对象 

// 想要拿到 result 的结果只能通过 then()
result.then(
  value =>{ console.log('onResolved()', value) },
  reason => { console.log('onRejected()', reason) }
)
这时输出结果为:onResolved() 1

Await 表达式

  • await表达式必须放在async函数里,否则会报错
  • 表达式右侧一般为Promsie对象,但也可以是其他的值
  • 如果表达式是Promiseawait返回的是Promise成功的值
  • 如果表达式是其他的值,则直接将此值作为await的返回值
  • 如果awaitPromise失败就会抛出异常,需通过try...catch来捕获处理

宏队列

  • 用来保存执行的宏任务(回调):
    • 定时器回调
    • DOM事件回调
    • Ajax回调
// 情景一:
function fn1(){
  return new Promise((resolve, reject)=>{
    setTimeout(()=>{
      resolve(1);
    },2000)
  })
}

async function fn2(){
  // await 右侧表达式为 Promise,得到的结果就是 Promise 成功的 value 
  const result = await fn1();
  console.log(result )
}

fn2();  // 等待 2 秒后 输出 1

// 情景二:
function fn1(){
  return 1;
}

async function fn2(){
  // await 右侧表达式为非 Promise ,得到的结果就是它本身
  const result = await fn1();
  console.log(result)
}

fn2();  // 直接输出 2

// 情景三:
function fn1(){
  return new Promise((resolve, reject)=>{
    setTimeout(()=>{
      reject(1);
    },2000)
  })
}

async function fn2(){
  try{
    // await 的 Promise 失败需要 `try...catch` 捕获来拿到错误信息,抛出异常也是如此
    const result = await fn1();
  }catch(error){
    console.log(error)
  }
}

fn2();  // 等待 2 秒后 输出 1

微队列

  • 用来保存待执行的微任务(回调):
    • Promise回调
    • MutationObserver回调

注意:

  • JS引擎首先必须先执行所有的初始化的同步任务代码
  • 每次准备取出第一个宏任务之前,都要将所有的微任务一个一个取出来执行

举 个 栗 子

setTimeout(() => {
  console.log(1)
}, 0);

Promise.resolve(2).then(
 value => { console.log(value ) }
)

输出顺序为:2 1

setTimeout是宏任务Promise是微任务,微任务执行先于宏任务即:每次准备取出第一个宏任务之前,都要将微任务逐个取出并执行。

setTimeout(() => {
  console.log(1)
}, 0);
setTimeout(() => {
  console.log(2)
}, 0);

Promise.resolve(3).then(
 value => { console.log(value ) }
)
Promise.resolve(4).then(
 value => { console.log(value ) }
)

输出顺序为:3 4 2 1

微任务执行先于宏任务,有多个同种任务时,按顺序依次执行。

setTimeout(() => {
  console.log(1)
  Promise.resolve(2).then(
   value => { console.log(value ) }
  )
}, 0);

Promise.resolve(3).then(
 value => { console.log(value ) }
)

console.log(4);

输出顺序为:4 3 1 2

1、JS引擎首先必须先执行所有的初始化同步任务代码即先输出 4
2、微任务执行先于宏任务即先输出 3
3、每次准备取出第一个宏任务之前,都要将微任务逐个取出并执行即输出 1 2
综上:执行顺序为:同步代码 =》微任务 =》 宏任务 =》宏任务里的微任务