对于javascript执行机制巩固
javascript执行机制
- 同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数;
- 当指定的事情完成时,Event Table会将这个函数移入Event Queue;
- 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行;
- 上述过程会不断重复,也就是常说的Event Loop(事件循环)。
怎么知道主线程执行栈为空?
js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去Event Queue那里检查是否有等待被调用的函数。
-
关于setTimeout(fn,ms):
- List item
- 即便主栈为空,0毫秒实际也达不到。根据HTML的标准,最低是4毫秒
-
关于setInterval(fn,ms):
- etInterval函数是每过指定时间,会有fn进入Event Queue。一旦setInterval的回调函数fn执行时间超过了延迟时间ms,那么就看不出时间间隔了
-
Promise与process.nextTick(callback) (node环境下的事件监听依赖libuv与前端环境不完全相同)
-
任务定义:
- macro-task(宏任务):包括整体代码script,setTimeout,setInterval,I/O, UI rendering 等
- micro-task(微任务):Promise,process.nextTick,Object.observe(已废弃), MutationObserver(html5新特性) 等
- 不同类型的任务会进入对应的Event Queue,比如setTimeout和setInterval会进入相同的Event Queue
事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
- 代码作为宏任务,进入主线程,第一轮事件开始
- 遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。
- 遇到Promise
- new Promise立即执行
- then函数分发到微任务Event Queue
- 遇到console.log(),立即执行
- 整体代码script作为第一个宏任务执行结束。
- 查看微任务,发现then在微任务Event Queue里面,执行
- 第一轮事件循环结束。
- 第二轮,从宏任务Event Queue开始
- Event Queue中setTimeout对应的回调函数,立即执行
- 结束
最后
- javascript是一门单线程语言,不管是什么新框架新语法糖实现的所谓异步,其实都是用同步的方法去模拟的
- 事件循环Event Loop是js实现异步的一种方法,也是js的执行机制。
本文转载于https://juejin.im/post/59e85eebf265da430d571f89