前言
作为浏览器脚本语言,JavaScript 的主要用途是与用户互动,以及操作 DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。
为何只能是单线程?
试想一下,假定JavaScript 同时有两个线程,一个线程在某个 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准呢
javascript是单线程语言,如何执行异步代码
js执行异步代码机制:
1.所有任务都在主线程上执行,形成一个执行栈;
2.主线程之外,还存在一个”任务队列”(task queue)。只要异步任务有了运行结果,就在”任务队列”之中放置一个事件;
3.一旦”执行栈”中的所有同步任务执行完毕,系统就会读取”任务队列”。那些对应的异步任务,结束等待状态,进入执行栈并开始执行;
4.主线程不断重复以上3步。
宏任务(macrotask)
script(整体代码)、setTimeout、setInterval、UI 渲染、 I/O、postMessage、 MessageChannel、setImmediate(Node.js 环境)
微任务
Promise.then、 MutaionObserver、process.nextTick(Node.js环境)
Event Loop(事件循环)中,每一次循环称为 tick, 每一次tick的任务如下:
1.执行栈选择最先进入队列的宏任务(通常是script
整体代码);
2.检查是否存在 Microtask,如果存在则不停的执行,直至清空 microtask 队列;
3.更新render(每一次事件循环,浏览器都可能会去更新渲染)
4.重复以上步骤
实践:
```
console.log('script start');
setTimeout(function () {
console.log("timeout");
});
new Promise(function(resolve,reject){
console.log(2)
resolve(3)
}).then(function(val){
console.log(val);
})
console.log('script end');
```
复制代码
打印顺序:script start->2->script end->3->timeout
源码中 MutationObserver 介绍
MO是html5新的API,是用来监听DOM变动的接口,他能监听一个DOM对象上发生的子节点删除、属性修改、文本内容修改等等。
var mo = new MutationObserver(callback);
var domTarget = 你想要监听的dom节点
mo.observe(domTarget, {
characterData: true //说明监听文本内容的修改。
})
复制代码
MutationObserver的回调(callback)是放在microtask中执行的。