引言
JavaScript 是单线程的,那么类似 setTimeout 的异步如何实现呢?
背景知识
setTimeout(fn, millisec)
millisec 毫秒后执行 fn 函数
注意:对于 setTimeout(fn, 0)的情况
例:
// 输出 2 3 1,而非 1 2 3
setTimeout(function () {
console.log(1);
}, 0);
console.log(2);
console.log(3);
虽然 setTimeout(fn, 0)的意思是 0ms 后执行 fn,也就是立刻执行
但是这个“立刻”指的是主程序执行完后的“立刻”
不仅 0 如此,所有的延迟执行 setTimeout 都是如此
如果有一堆这样的函数,它们会被放入等待队列中
解释
Js 单线程,但是浏览器内核是多线程的
一个浏览器至少有三个常驻线程:
- JavaScript 引擎线程
- GUI 渲染线程
- 浏览器事件触发线程
除此之外还有:
- 定时器线程,专门处理 setInterval 和 setTimeOut
- 异步 HTTP 请求线程
其中,JS 引擎线程是主线程
当遇到 setTimeout 函数,JS 引擎线程则将其交给定时器线程去执行,自己则执行下面的代码
定时器线程计时结束后,会将回调函数放入任务队列
(不是立即执行!)
主线程处理完了自己的任务后,才会去执行任务队列里的任务
虽然都在任务队列中,也有宏任务与微任务之分
宏任务和微任务
- 宏任务
- 定时器 setTimeout setInterval
- 微任务
- Promise .then/catch/finally 的执行
- 执行同步代码
- 清空微任务队列
- 执行宏任务.如果这期间遇到宏任务/微任务,塞进对应的层级里即可
注:Promise 里面执行的逻辑直接执行就好,可认为是同步任务。只有.then/catch/finally 才是微任务
function app() {
setTimeout(() => {
console.log('1-1');
Promise.resolve().then(() => {
console.log('2-1');
});
});
console.log('1-2');
Promise.resolve().then(() => {
console.log('1-3');
setTimeout(() => {
console.log('3-1');
});
});
}
app();
运行结果
1-2
1-3
1-1
2-1
3-1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iAhsqjUq-1655706527186)(https://segmentfault.com/img/remote/1460000039055445)]
参考:
https://segmentfault.com/a/1190000039055443