使用async...await以及js的事件循环机制

本文介绍了JavaScript中async/await的使用方法,包括其返回的Promise对象,await关键字的阻塞与非阻塞特性,以及与Promise和事件循环机制的关系。同时详细讲解了同步、宏任务和微任务的执行顺序。
摘要由CSDN通过智能技术生成


前言

async…await的使用以及事件循环机制(同步,宏任务,微任务)的执行顺序


提示:以下是本篇文章正文内容,下面案例可供参考

一、async…await是什么?

在 JavaScript 中,使用 asyncawait 关键字可以简化异步操作的处理。async 用于定义一个返回 Promise 的异步函数,而 await 用于等待一个 Promise 对象的解析结果。

二、使用过程

1.async函数返回的是一个promise对象

代码如下(示例),下面两种方法是等效的:

// 方法1
function f() {return Promise.resolve('TEST');
}// asyncF is equivalent to f!

// 方法2
async function asyncF() {return 'TEST';
}
 async function timeout() {
      return 'hello world!'
    }
    timeout().then(val => {
      console.log(val)
    })
    console.log('我虽然在后面,但是先执行')
   
}

那么要想获取到async 函数的执行结果,就要调用promise的then 或 catch 来给它注册回调函数

原来async 函数返回的是一个promise 对象,并且Promise还有state和result,如果async函数中有返回值,当调用该函数时,内部会调用Promise.resolve()方法把它转化成一个promise对象作为返回,但如果timeout函数内部抛出错误呢? 那么就会调用Promise.reject() 返回一个promise 对象

2.await 等到了要等的,然后呢?

await 等到了它要等的东西,一个 Promise 对象,或者其它值,然后呢?

1)如果它等到的不是一个Promise对象,那么await表达式的运算结果就是它等到的东西。
2)如果它等到的是一个Promise对象,await就忙起来了,它会阻塞函数后面的代码,等着Promise对象resolve,然后得到resolve的值,作为await表达式的运算结果。

await 优势在于处理 then 链,使代码看起来像同步代码一样

3.await处理

当遇到 await 时,会阻塞函数内部处于它后面的代码(而非整段代码),去执行该函数外部的同步代码;当外部的同步代码执行完毕,再回到该函数执行剩余的代码。

async function fn1 (){
  console.log(1)
  await fn2() // fn2进入微任务队列等待执行
  console.log(2) // 阻塞
}
async function fn2 (){
  console.log('fn2')
}
fn1()
console.log(3)

// 输出结果:1,fn2,3,2

上面的例子中,await 会阻塞它下面的代码(即加入微任务队列),先执行 async 外面的同步代码,同步代码执行完,再回到 async 函数中,再执行之前阻塞的代码。


注意
1)await必须写在async函数中, 但async函数中可以没有await
2)如果await的promise失败了, 就会抛出异常, 需要通过**try…catch**来捕获处理

总结

async/await or promise使用时到底选择哪个呢?
大部分复杂情况下async/await 的确是最优解,个人觉得也不是所有情况下都是 async/await 写起来更爽,最不爽的就是他的错误处理,try…catch这个代码看起来就很奇怪(当然也有很多人喜欢这种错误处理方式)。所以我个人的习惯,当只有一个异步请求,且需要做错误处理的情况下,更倾向于使用 promise。比如

// promise
getInfo()
  .then(res => {
    //do somethings
  })
  .catch(err => {
    //do somethings
  })

// async/await
try {
  const res = await getInfo()
  //do somethings
} catch (error) {
  //do somethings
}

async…await和 .then (promise) 可以不必同时出现

三、JS的事件循环机制

(Event Loop)-- 同步 . 宏任务 . 微任务执行顺序:

实例一:

console.log('同步代码1');

async function async1 () {
   console.log('async1 start')
   await async2()
   console.log('async1 end')
}
async function async2 () {
   console.log('async2')
}
async1()
    
setTimeout(() => {
    console.log('setTimeout1')
    new Promise((resolve) => {
        console.log('Promise 1')
        resolve()
    }).then(() => {
        console.log('promise.then1')
    })
}, 10)

new Promise((resolve) => {
    console.log('同步代码2, Promise 2')
    setTimeout(() => {
        console.log('setTimeout2')
    }, 10)
    resolve()
}).then(() => {
    console.log('promise.then2');
    setTimeout(() => {
        console.log('setTimeout3')
    }, 10);
    new Promise((resolve) => {
        console.log('Promise 3')
        resolve()
    }).then(() => {
        console.log('promise.then3')
    });
})

console.log('同步代码3');

/* 宏任务队列中第1个宏任务script的打印:*/
// 同步代码1
// async1 start
// async2
// 同步代码2, Promise 2
// 同步代码3
// async1 end
// promise.then2
// Promise 3
// promise.then3

/* 宏任务队列中第2个宏任务setTimeout1的打印:*/
// setTimeout1
// Promise 1
// promise.then1

/* 宏任务队列中第3个宏任务setTimeout2的打印:*/
// setTimeout2

/* 宏任务队列中第3个宏任务setTimeout3的打印:*/
// setTimeout3

注意:

1、promise中的回调函数立刻执行,then中的 回调函数 会推入微任务队列中,等待执行栈所有任务执行完才执行。

2、通过 async 定义的函数在 执行栈 中执行,await 将异步程序变成同步,所以await 后面执行的程序需要等到await定义的函数执行完毕才执行,需要放入微任务队列中等待的。(await在等待后面的函数执行的过程中会先执行下面的同步任务,执行完之后再执行await后面的代码)

实例二:

queueMicrotask(() => {
  console.log("queueMicrotask1")
});

queueMicrotask表示开启一个微任务,与Promise.then函数效果一致

实例三:

async function async1 () {
  console.log('async1 start')
  await async2();
  console.log('async1 end')
}
 
async function async2 () {
  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

函数只有调用的时候才会推入调用栈中,所以最先执行的是 console.log,即输出 script start,然后setTimeout函数(“setTimeout”)放入宏任务队列中等待,调用async1函数,输出 async1 start,执行async2函数,输出async2,(“async1 end”)放入微任务队列中等待,继续向下执行Promise函数,输出 promise1,then函数中的(“promise2”)放入微任务队列中等待,输出 script end。

调用栈的程序都已执行完毕,此时开始执行微任务队列中的程序,依次输出 async1 end、promise2。

结论:通过async定义的函数在调用栈中执行,await 将异步程序变成同步,所以await后面执行的程序需要等到await定义的函数执行完成才执行,需要在微任务队列中等待

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值