JavaScript任务队列的执行

本文作者:IMWeb went 原文出处:IMWeb社区 未经同意,禁止转载

1.事件循环(Event Loop)机制

众所周知,JavaScript的一大特点就是是单线程,所有任务都需要在主线程里排队等待执行。

而JavaScript里的任务又分为同步任务和异步任务两种,基于事件循环(Event Loop)机制执行任务。

同步任务作为首要任务会在主线程里执行,异步任务则被“发配”到由另一个线程管理的任务队列中等待处理。异步任务符合条件(比如ajax请求到数据,setTimeout延时到期)后,会在任务队列中添加可执行“事件”,等待主线程中的同步任务执行完毕到任务队列里读取当前可执行的任务,将其加入主线程中执行,以此循环。

根据HTML Standard中的描述,一个事件循环中的执行流程大致如下。

1.选择最早的任务

2.设置事件循环中当前任务为上一步中选择的任务

3.执行该任务

4.将事件循环中的当前任务重新设置为空

5.将主线程中执行的任务移除

6.执行Microtask中的任务

7.执行页面渲染步骤,更新UI

2.JavaScript中的异步任务

能在JavaScript中执行异步任务的一般有以下这几种方法。

(1)最常见的有定时器函数setTimeout、setInterval和setImmediate

setTimeout和setInterval都是指定在time后在任务队列里添加相关“事件”,通知主线程把相应任务放到主线程中去执行。

setImmediate作为一个新的API,可以马上将相关“事件”添加到任务队列里,通知主线程把相应任务放到主线程中去执行。

(2)Promise

Promise.then中传入了一个回调函数,将在Promise对象进行决议(resolve/reject)后进行异步回调。

(3)MutationObserver

MutationObserver提供了监听在特定范围内DOM树发生变化事件的能力,并提供回调函数可以作出适当反应的能力。

(4)process.nextTick

process.nextTick是NodeJS中的API,提供了即使执行回调的能力。

// 观察一下一段代码
console.log('Start');

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

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

let observer = new MutationObserver(()=>{
    console.log('MutationObserver ');
});
let target = document.querySelector('#id');
observer.observe(target, config);
/* target进行某些变化*/

console.log('End');

// 输出
// Start
// End
// Promise
// MutationObserver
// setTimeout

不是说异步任务完成后会依次通知主线程到任务队列里获取可执行回调到主线程中执行吗?按照逻辑应该是 setTimeout是任务队列中最早的任务,主线程应该首先执行setTimeout的回调。

如果在Node中加代码后加上process.nextTick,process.nextTick的回调仍然在setTimeout回调之前执行,这个顺序是怎么确定的呢?

3.JavaScript中的任务队列

通过阅读Promise/A+规范,可以得知异步的实现可分为两个机制,分别是macro-task和micro-task。

Macrotasks包括: script(整体代码)、setTimeout, setInterval, setImmediate, I/O, UI Rendering;

Microtasks包括: process.nextTick, Promise, Object.observe, MutationObserver。

Macrotasks、Microtasks执行机制:

1.主线程执行完后会先到micro-task队列中读取可执行任务

2.主线程执行micro-task任务

3.主线程到macro-task任务队列中读取可执行任务

4.主线程执行macro-task任务

5....转到Step 1

这里注意的是,UI Rendering是在micro-task之后执行,需要在UI渲染之前执行的逻辑,一般采用micro-task异步回调方式进行调用。

同样,micro-task队列不宜过长,给micro-task队列添加过多回调阻塞macro-task队列的任务执行是小事,重点是这有可能会阻塞UI Render,导致页面不能更新。浏览器也会基于性能方面的考虑,对micro-task中的任务个数进行限制。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏河湾欢儿的专栏

Vue-router(路由)

2.定义(注册)路由跳转的组件----使用全局扩展的方式,用其他创建组件的方式也可以 在这里,进行了一个赋值操作,用一个变量名保存组件中所有的内容

15120
来自专栏从零开始学自动化测试

appium+python自动化42-微信公众号webview操作

上一篇已经解决切换到微信公众号的webview上了,但是定位webview上元素的时候一直提示找不到,打印page_source也找不到页面上的元素,这个问题困...

26810
来自专栏十月梦想

node项目中文乱码解决

上一篇的第一个node项目成功运行,但是设置res.write('你好,世界'),浏览器运行出现乱码

9830
来自专栏魏艾斯博客www.vpsss.net

宝塔面板安装后需要改掉默认端口和登陆账号

1.1K20
来自专栏枕边书

JavaScript Alert 函数执行顺序问题

问题 ---- 前几天使用 JavaScript 写 HTML 页面时遇到了一个奇怪的问题: 我想实现的功能是通过 confirm() 弹窗让用户选择不同的需求...

33940
来自专栏前端小作坊

网页上的复制与剪切

IE 10及以上的版本修改了Document.execCommand()方法,增加了对剪切和复制的支持。Chrome从43版本开始也支持了这项特性。

14220
来自专栏睿哥杂货铺

玩转编程语言:基于Node.js构建自定义代码生成器

在真实的软件开发过程中,无论使用何种编程开发语言,都不可避免的会遇到代码重复的问题。如何处理重复的问题,可以选择情怀(手动再敲一遍),也可以选择 Copy-to...

37650
来自专栏菜鸟计划

vue小白快速入门

一、vue是什么 Vue 是一套用于构建用户界面的渐进式框架。 压缩后仅有17kb 二、vue环境搭建 你直接下载并用 <script> 标签引入,Vue 会被...

30840
来自专栏程序员的诗和远方

tips-解决base标签造成SVG效果失效

之前写了使用SVG实现一个骚气的圆环: 一个比想象中更骚气的圆-svg实现。后来上线过程中发现渐变的效果出不来,原来是html base标签和内联SVG同时使用...

32550
来自专栏Puppeteer学习

一步一步学习Vue(十一)

18420

扫码关注云+社区

领取腾讯云代金券