-
javascript事件循环机制从何而来(产生原因):
因为javascript是单线程的,javascript自上而下执行,但是不一定都是同步代码,中间会遇到一些异步的代码,比如定时器。那么这时候,单线程的javascript该如何应对呢?
于是就想了个解决办法,用事件循环(event loop)来应对异步。
补充:为什么javascript会被设计成单线程?
假如说。javascript是多线程的,有两个线程同时去操作一个DOM,期中一个对这个DOM加一个属性,而另一线程要删除这个DOM,那么以哪个线程为准呢?这样就会产生许多复杂的问题要处理,
所以就设计成单线程最合理。虽然h5,提出了web worker新标准,但是它受主线程限制,它是主线程的一个子线程。
下面来说一下javascript 事件循环机制(event loop)
1、执行栈
2、事件队列(任务队列)
任务又分为宏任务和微任务
事件队列: 异步代码的执行,遇到异步事件不会等待它返回结果,而是将这个事件挂起,继续执行执行栈中的其他任务。当异步事件返回结果,将它放到事件队列中,被放入事件队列不会立刻执行起回调,而是等待当前执行栈中所有任务都执行完毕,主线程空闲状态,主线程会去查找事件队列中是否有任务,如果有,则取出排在第一位的事件,并把这个事件对应的回调放到执行栈中,然后执行其中的同步代码。
主线程会依次执行执行栈内的代码,遇到异步代码(宏任务|微任务),就会将它们放到事件队列中(任务队列中),如果是宏任务,就放在宏任务队列,如果是微任务,就放在微任务队列。
如果主执行栈执行完毕,会从事件队列中去取事件,放在执行栈中执行。
事件队列遵守先进先出原则。
先执行宏任务,如果本次宏任务执行产生了微任务,会先把这个微任务执行完,再执行下一个宏任务
宏任务有哪些?
- script(整体代码)
- setTimeout()
- setInterval()
- postMessage
- I/O
- UI交互事件
微任务有哪些?
- new Promise().then(回调)
- MutationObserver(html5 新特性)
简单总结一下顺序
执行宏任务,然后执行该宏任务产生的微任务,若微任务在执行过程中产生了新的微任务,则继续执行微任务,微任务执行完毕后,再回到宏任务中进行下一轮循环。
练习一道题:
console.log('start') setTimeout(function() { console.log('setTimeout') }, 0) Promise.resolve().then(function() { console.log('promise1') }).then(function() { console.log('promise2') }) console.log('end')
执行顺序:
1、全局代码压入执行栈执行,输出 start
2、setTimeout压入 macrotask队列,promise.then 回调放入 microtask队列,最后执行 console.log('end')
,输出 end
3、调用栈中的代码执行完成(全局代码属于宏任务),接下来开始执行微任务队列中的代码,执行promise回调,输出 promise1
, promise回调函数默认返回 undefined, promise状态变成 fulfilled ,触发接下来的 then回调,继续压入 microtask队列,此时产生了新的微任务,会接着把当前的微任务队列执行完,此时执行第二个 promise.then回调,输出 promise2
4、此时,microtask队列 已清空,接下来会会执行 UI渲染工作(如果有的话),然后开始下一轮 event loop, 执行 setTimeout的回调,输出 setTimeout
最后输出结果:
- start
- end
- promise1
- promise2
- setTimeout
-