首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >关于JS执行顺序

关于JS执行顺序

作者头像
kifuan
发布2022-10-24 16:25:57
发布2022-10-24 16:25:57
7.1K0
举报
文章被收录于专栏:随便写写-kifuan随便写写-kifuan

源码

点击这里前往Github获取源码。

背景

众所周知,JS是单线程语言,但它支持异步操作,其核心机制就是JS引擎的事件循环

先上一段代码:

代码语言:javascript
复制
console.log(1)

setTimeout(() => {
    console.log(2)
})

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

console.log(5)

// 1 3 5 4 2

背后的原因就是事件循环中的宏任务微任务

原理

总的来说,流程图如下:

Promise中的代码块是立即执行的。

下列代码可以证明:

代码语言:javascript
复制
console.log(1)

new Promise(() => {
    console.log(2)
})

console.log(3)

// 1 2 3

这部分很简单了,从上到下同步执行。

Promise后的then传入的方法是微任务

下面代码为V8引擎源码,注意它是用V8内部语言Torque编写,我们只需要看它是继承了Microtask即可知它是一个微任务,无需在意更多细节:

代码语言:javascript
复制
@generateCppClass
extern class PromiseResolveThenableJobTask extends Microtask {
  context: Context;
  promise_to_resolve: JSPromise;
  thenable: JSReceiver;
  then: JSReceiver;
}

所以说它会在最外层代码执行完后再去执行。

setTimeout或者setInterval都是宏任务

我这里实在是没找到源码哪里表明了这个东西,于是直接在NodeJS里换个方式证明一下。

NodeJS中,process.nextTick可以设置一个微任务,使用下列代码测试:

代码语言:javascript
复制
setTimeout(() => {
    console.log(1)
})

process.nextTick(() => {
    console.log(2)
})

process.nextTick(() => {
    console.log(3)
})

console.log(4)

// 4 2 3 1

我们把setTimeout放在最开始,而且不管设置了几次nextTicksetTimeout里的函数体总是最后执行的,由此可见它的确是一个宏任务。

更复杂一点

不管我的Promise怎么组合,怎么套,由于setTimeout设置的是宏任务,所以它始终在这些微任务都执行完成之后才会运行:

代码语言:javascript
复制
setTimeout(() => {
    console.log(1)
})

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

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

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

console.log(5)
// 5 2 3 4 1

可以看出,2 3 4全都是微任务,而5是最外层同步执行的代码,1是由setTimeout设置的下一个宏任务。

总结

再回到开头的程序:

代码语言:javascript
复制
console.log(1)

setTimeout(() => {
    console.log(2)
})

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

console.log(5)

// 1 3 5 4 2

因为1,3,5都是同步执行的,所以它们按顺序排列; 2是宏任务,会放到下一次事件循环时执行; 4是微任务,在首次运行时就把它添加到了微任务队列中,所以在下一次事件循环之前就会被执行。

通过这样的事件循环,使得单线程的JS也可以拥有异步的能力,使得如AJAX请求这样费时间的操作可以被安排到后面来执行,不影响页面的加载和渲染。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 源码
  • 背景
  • 原理
  • 更复杂一点
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档