一. 单线程
1. 单线程
首先,js是一个非阻塞的单线程脚本语言;非阻塞即执行异步任务,主线程会挂起任务,等待异步任务执行完成后按照一定的规则执行回调函数
2. 堆和栈
js的变量存放于堆或者栈中;堆中存放对象,栈中存放基本变量和对象的指针
二. 执行栈和事件队列
1. 同步方法调用
(1)脚本第一次执行,js引擎解析代码,将同步代码依次排列在执行栈中;
(2)一系列方法依次调用,一次只能执行一个方法;
(3)调用js方法;
(4)创建方法对应的执行环境,即上下文(context)。包括方法私有域,上层作用域指向、作用域内变量、作用域this对象、方法的参数;
(5)方法执行会向执行栈中加入这个方法的执行环境,在这个执行环境中还可以调用其他方法,甚至是自己,其结果是在执行栈中再添加一个执行环境。
2. 异步方法调用-事件队列
(1)js引擎将异步事件挂起,继续执行执行栈中的其他任务;
(2)异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,称之为事件队列;
(3)被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。
(4)如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码…,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。
3.宏任务队列和微任务队列
微任务:Promise、process
宏任务:setInterval()、setTimeout()
在每次轮训检查中,各观察者的优先级分别是:
4.队列事件优先级
idle观察者 > I/O观察者 > check观察者。
idle观察者:process.nextTick
I/O观察者:一般性的I/O回调,如网络,文件,数据库I/O等
check观察者:setImmediate,setTimeout(setTimeout>setImmediate)
同一优先级先入先出,不同优先级process>promise.then>setTimeout>setImmediate
三. 面试题目
setTimeout(function() {
console.log(1)
}, 0);
new Promise(function executor(resolve) {
console.log(2);
for (var i = 0; i < 10000; i++) {
i == 9999 && resolve();
}
console.log(3);
}).then(function() {
console.log(4);
});
console.log(5);
// 2 3 5 4 1
setImmediate(function () {
console.log('1');
});
setTimeout(function () {
console.log('2');
},0);
setImmediate(function () {
console.log('4');
});
setTimeout(function () {
console.log('44');
},0);
console.log('3');
//输出
3
2
44
1
4
参考地址:https://www.cnblogs.com/cangqinglang/p/8967268.html
https://github.com/fwon/blog/issues/36