JavaScript中的事件循环方式
js是单线程,非阻塞,试想如果是多线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?所以,为了避免复杂性,从一诞生,JavaScript就是单线程。
js的事件循环分为主线程(同步)和任务队列(异步),任务队列里又分为宏任务和微任务
1.宏任务(macro-task):
script(整体代码),setTimeout,setInterval,setImmediate。
优先级: setImmediate > setTimeout / setInterval
2.微任务(micro-task):
Promise,mutationObserve(观察DOM树结构发生变化时,做出相应处理),process.nextTick(Node.js 环境)。
优先级:process.nextTick > Promise > MutationObserver
概述原理
同步>微任务>宏任务
1.宏任务、微任务都是任务队列,一段代码执行时,会先执行宏任务中的同步代码。
2.进行第一轮事件循环的时候会把js脚本当成一个宏任务来运行。
3.如果执行中遇到setTimeout之类宏任务,那么就把这个setTimeout内部的函数推入宏任务的队列中,下一轮宏任务执行时调用。
4.如果执行中遇到 promise.then() 之类的微任务,就会推入到微任务队列中,在本轮宏任务的同步代码都执行完成后,依次执行所有的微任务。
5.当执行完全部的同步脚本以及微任务队列中的事件,这一轮循环就结束了,开始第二轮循环,依次循环往复。
案例解析
<script> setTimeout(() => { console.log('4') }, 100) new Promise((resolve) => { console.log('1') resolve("成功") }).then(data => { console.log(data) }) console.log('2') </script>
解析
1.这段代码作为宏任务,进入主线程。
2.先遇到setTimeout之类宏任务,那么就把这个setTimeout内部的函数推入宏任务的队列中,下一轮宏任务执行时调用。
3.接下来遇到了Promise,同步代码立即执行,回调函数分发到微任务队列中。
4.遇到console.log(‘2’),立即执行,查看有无微任务,有一个then的回调函数,立即执行。
5.第一轮宏任务执行结束。
6.开始第二轮宏任务,执行宏任务中的setTimeout函数。
将以上代码升级下:
setTimeout(() => { console.log('1') }, 1000) new Promise((resolve) => { console.log('2') setTimeout((params) => { resolve("4") console.log("3"); }, 100) }).then(data => { console.log(data) }) console.log('5')
能否先将promise.then分发到微任务中?
答案是不能,因为只有resolve成功回调之后才能执行.then,而现在resolve在setTimeout宏任务中,只有等setTimeout执行完之后才能执行.then中的微任务
解析
1.这段代码作为宏任务,进入主线程。
2.先遇到等待时间为1000ms的setTimeout,记为s1,并且把这个setTimeout内部的函数推入宏任务的队列中,下一轮宏任务执行时调用。
3.接下来遇到了Promise,同步代码立即执行,但其内部包含一个等待时间为100ms的setTimeout,记为s2,并且promise的resolve也在其中,也把它放在下一轮的宏任务中。
4.遇到console.log(‘5’),立即执行。
5.第一轮宏任务执行结束。查看当前有没有可执行的微任务,没有则执行宏任务。
6.开启第二轮宏任务,发现有两个宏任务,比较等待时间长短,时间短的先执行,先执行s2,发现其中有微任务promise.then,立即执行,再执行s1。
最后的执行顺序为2 5 3 4 1
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
addEventListener和attachEvent二者绑定的执行函数中的this不相同
写 addEventListener 和 attachEvent 区别的博文不少,不过大部分都把重点放置于前者是Firefox chrome,后者只是存在于IE系列中2012-12-12表单元素的submit()方法和onsubmit事件应用概述
表单元素拥有submit方法,同时也具有onsubmit事件句柄,用于监听表单提交。可以使用elemForm.submit();方法触发表单提交,感兴趣的朋友可以了解下,或许对你有所帮助2013-02-02详解Javascript ES6中的箭头函数(Arrow Functions)
箭头函数,若有了解过coffeeScript的同学,或许对此印象深刻,因为它可以让语法省略不少,特别是对于回调函数,会让代码更清晰简洁。下面让我们一起来学习学习ES6中的箭头函数。2016-08-08
最新评论