javascript是单线程的语言,
能够单线程将理解为只有一条车道,在车道里后面的车在等前面的车经过后,才能经过.
即当前面的程序没有执行,后面的程序也不能执行.javascript
执行栈像"车道",被执行的程序会放入执行栈里,
但它的执行的顺序是,后面进来的程序先执行.前端
视频源地址vue
在线程中有不少等待运行的任务(程序,而执行栈只会放入一个任务.
其余可运行任务会放入任务队列中.
这里虽然说是个队列, 它的执行的顺序,不会先进的程序先执行.
每一个event loop都会有一个或多个任务队列java
javascript是单线程,但也能实现异步,这种实现基与页面提供不少API,如(setTimeout, ajax, addEventListener ...)
这些都是异步函数,也就是说,运行到异步函数时,
把异步函数里闭包放入web api里,等待正确的时机,
web api会把闭包放入task queue里执行.git
macro task有setTimeout ,setInterval, setImmediate,requestAnimationFrame,I/O ,UI渲染...
task queue 是由不少个macro task组成的队列,github
micro task有Promise, process.nextTick, Object.observe, MutationObserver...
每一个event loop都会有一个micro taskweb
执行流程ajax
<script>// 建立macro task, 由于stack 为null, 执行 (function test() { setTimeout(() => { // 建立macro task, 当前task queue['第一setTimeout闭包'] console.log(4) }, 0); new Promise(resolve => { console.log(1); // 执行, 控制台 1 for(var i = 0; i < 10000; i++) { i == 9999 && resolve(); // 建立micro task, 当前micro task queue['第一then闭包'] } console.log(2); // 执行, 控制台 1 2 }).then(() => { console.log(5); return new Promise(resolve => { resolve() }) }).then(() => { console.log(6) }); console.log(3); /* 执行, 控制台 1 2 3, 第一个script标签建立的macro task结束 运行micro task queue首个micro task === 第一then闭包 执行, 控制台 1 2 3 5, 并建立了micro task 放入 micro task queue['第二then 闭包'] 运行micro task queue首个micro task === 第二then 闭包 执行, 控制台 1 2 3 5 6 */ })() </script> <script>// 建立macro task, 由于stack 为null, 执行 (function test2() { setTimeout(function () { // 建立一个macro task 放入 task queue['第一setTimeout闭包' '第二setTimeout闭包'] console.log(42) }, 0); new Promise(function executor (resolve) { console.log(12); // 执行 控制台1 2 3 5 6 12 for(var i = 0; i < 10000; i++) { i == 9999 && resolve(); // 建立micro task, 当前micro task queue['第一then闭包'] } console.log(22); // 执行 控制台1 2 3 5 6 12 22 }).then(function() { console.log(52); }); console.log(32); /* 执行, 控制台 1 2 3 5 6 12 22 32, 第二个script标签建立的macro task结束 运行micro task queue首个micro task === 第一then闭包 执行, 控制台 1 2 3 5 6 12 22 32 52, 查看micro task queue首个task为null, 查看task queue task queue为空,向web 获取可执行的任务['第一setTimeout闭包', '第二setTimeout闭包'] 运行task queue首个 macro task === 第一setTimeout闭包 执行, 控制台 1 2 3 5 6 12 22 32 52 4 查看micro task queue首个task为null, 查看task queue 运行task queue首个 macro task === 第二setTimeout闭包 执行, 控制台 1 2 3 5 6 12 22 32 52 4 42 */ })() </script>
在macro/micro task 进入执行栈时,中间应该会有一个缓存区,
例如api
<script> // 建立macro task,进入执行栈 var a = () => { console.log('a'); } var b = () => { console.log('b'); } a(); //这时函数A进入stack,执行,打印出a b(); //这时函数B进入stack,执行,打印出b </script>
若是是把整个macro task放入执行栈,
按后进程序先执行的机制, 应该会先打印'b',
但打印的是'a',说明函数b是等函数a执行完后再进入执行栈的,
因此在macro task 会把里面的函数拆分为一个执行的队列,放入执行栈里.缓存
https://github.com/ccforward/cc/issues/48
https://juejin.im/entry/596d78ee6fb9a06bb752475c
做者有一年半的前端开发经验,比较擅长性能优化和vue,喜欢对各类原理的深究,
喜欢篮球和电影
若是有趣味相投能够加入微信群