js中async与await易懂的介绍(含对执行栈和消息队列的简单介绍)

关于Promise的前置知识,见这篇:http://t.csdnimg.cn/EFZl2

async与await

async与await使异步操作可以以同步代码的形式进行写作
主要用来简化Promise的写法
不用再写成

let promise = new Promise(...);
promise.then(someFunc);

可以写为

await new Promise(...);
someFunc();

async

async关键字用于声明异步函数

async function myAsync(){};
let myAsync = async () => {};

可以看做只是一个标识符。async function中的代码仍是同步执行,直到遇到await。

async函数会返回:

  • 没有显式返回值:返回undefined
  • 有显式返回值,不是Promise对象,则将ret包装为Promise.resolve(ret)
  • 有显式返回值,是Promise对象,返回该Promise对象

await

await暂停函数执行,将该语句(及其之后的代码)转变为异步的。

Promise返回值

await promise 返回 promise的“返回值”

let ret = await new Promise((resolve, reject) => {
            resolve("I'm ret");
        })//ret为”I’m ret”

try catch

使用try catch可以分别处理Promise resolve和reject的情况
在promise resolve 的情况下,await promise 返回 promise的“返回值”
在promise reject的情况下,await promise 抛出异常,用catch(error)可以得到promise的“返回值”

error();
async function error() {
    try {
        let ret = await new Promise((resolve, reject) => {
            reject("I'm error");
        })
        console.log(ret);
    } catch (error) {
        console.log(typeof(error));
        console.log(error);
    }
}

同步与异步

当 JavaScript 引擎执行代码时,会将同步任务添加到执行栈(Execution Stack)中依次执行。而当遇到异步操作时,如定时器、事件监听、网络请求等,这些异步操作的回调函数不会立即执行,而是会被放入消息队列中等待执行。
消息队列的执行是由事件循环机制控制的,它会持续地监测执行栈是否为空。当执行栈为空时,事件循环会从消息队列中取出一个任务,将其添加到执行栈中执行。这样就实现了异步任务的执行。

执行栈 Execution Stack

执行栈是 JavaScript 引擎中的一个栈结构,用于存储执行上下文(Execution Context)。在执行 JavaScript 代码时,每个函数调用都会创建一个执行上下文,并压入执行栈中。执行栈遵循后进先出(LIFO)的原则,即最后压入栈的执行上下文会最先执行。

当函数执行完毕时,其对应的执行上下文会从执行栈中弹出,控制权回到上一个执行上下文中。这样依次执行,直到执行栈为空,JavaScript 引擎认为整个任务执行结束。

消息队列 Message Queue

消息队列是 JavaScript 引擎中用于存放异步任务的数据结构。当发生异步操作时,其回调函数会被放入消息队列中等待执行。
比如setTimeout的回调函数在等待x ms后才会被调用,所以它也是会在等待x ms后才会被放进消息队列

消息队列采用先进先出(FIFO)的原则,即先进入队列的任务会先被执行。但它并不会直接影响到执行栈中的任务执行顺序。只有当执行栈为空时,事件循环(Event Loop)才会检查消息队列,并将其中的任务移至执行栈中执行

通常,消息队列中的任务可以分为两类:

  • 宏任务(Macro Task):
    通常包括整体代码 script 、setTimeout 、setInterval 、setImmediate 、I/O 、UI rendering。
  • 微任务(Micro Task)(优先):
    通常包括Promise 、process.nextTick 、MutationObserver。

在事件循环中,会先处理所有的微任务,直到微任务队列为空,然后再处理宏任务,依次循环执行。这保证了微任务优先级高于宏任务,并且微任务会在当前任务执行结束后立即执行,而不会等待其他任务。

*Q:哪怕是嵌套的函数,在最里层的异步函数也会等到所有外层同步代码都结束了才能开始?
A:异步函数的内容会在可用时 就被放进 消息队列,也就是说比如setTimeout(callback, 1000ms)中的callback会在1s之后就被放进消息队列,与同步代码无关
但是,只有执行栈空了,也就是所有同步代码(不管内外层)都执行完了,Event loop才会去检查消息队列。这时callback才能被取到执行栈中,开始执行。
所以,callback不需要等到所有同步代码都结束 就能被放入消息队列
但,callback需要等到所有同步代码都结束,才能被执行。

事件循环 Event Loop

事件循环是 JavaScript 引擎中负责处理异步任务的核心机制。它会持续地监测执行栈的状态,当执行栈为空时,会检查消息队列中是否有待执行的任务。*

如果消息队列中有任务等待执行,事件循环会将其取出并放入执行栈中执行。执行完毕后,继续检查执行栈和消息队列的状态,重复这个过程,直到两者都为空。

通过事件循环,JavaScript 引擎实现了异步任务的执行,保证了程序在等待异步操作完成时,能够继续执行其他任务,提高了整个程序的性能和响应速度。

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值