1。JS单线程并不是说JS只有一个线程,而是说同一时间只能有一个线程工作。2、在js中,除了主线程之外,还有其他的线程,比如事件循环线程、定时器触发线程、http异步线程、浏览器事件线程。3.在js主线程中,分为两个子线??程,js引擎线程和GUI渲染线程。这两个线程是互斥的,一次只能执行一个,要么执行js,要么渲染html4,在任务队列中,分为宏任务和微任务。每次执行任务队列时,先执行microtask,再执行macrotask。5、通常宏任务是指setTimeout、setInterval、XMLHttprequest、fetch等回调。微任务是指回调,例如Promise和MutationObserver。6、如果定时器触发线程、http异步线程、浏览器事件线程中没有回调,则不会放入队列。7、事件循环线程必须等待主线程中的同步代码执行结束,才能去任务队列中取另一个任务放入主线程中执行。//index.jsconsole.log('a');Promise.resolve().then(()=>{console.log('b');});setTimeout(()=>{console.log('c');},0);setTimeout(()=>{console.log('d');Promise.resolve().then(()=>{console.log('e');});},0);控制台日志('f');下面是上面代码的执行逻辑:遇到console.log('a');同步代码,执行,输出一个;遇到Promise,异步代码,放任务队列。因为它是一个promise回调,所以它是一个微任务。标记microtask1遇到setTimeout时执行,放入customizertrigger线程,timer触发线程在倒计时结束时维护,将callback放入任务队列。又因为setTimeout的回调是一个宏任务。标记为宏任务1,遇到setTimeout执行,放入customizer触发线程,回调放入任务队列。因为setTimeout的回调属于宏任务。标记为宏任务2遇到console.log('f');同步代码,执行,输出f此时主线程中的同步代码已经执行完毕,控制台输出a,f。主线程是空的。这时候eventloop线程发现任务队列里有东西,分别是microtask1,macrotask1,macrotask2。按照先执行microtasks,再执行macrotasks的顺序,先执行microtask1,即是,()=>{console.log('b');}放入主线程,js执行。输出b.这个时候主线程已经执行完了,又是空的。此时任务队列中有宏任务1和宏任务2。由于宏任务1先放入,所以遵循队列的先进先出顺序。先将宏任务1放入主线程。即()=>{console.log('c');},输出c,然后判断队列中是否有微任务,有则全部执行。如果没有,继续执行宏任务2。将宏任务2放入主线程,即()=>{console.log('d');Promise.resolve().then(()=>{console.log('e');});}输出d,遇到promise,异步代码,放入microtask队列。标记为Microtask2。此时主线程再次为空。此时任务队列只有microtask2,没有其他的macrotasks和microtasks。最后,执行微任务2。即()=>{console.log('e');},输出e总结一下:最终输出结果是afbcde注:1、上面的setTimeout(()=>{});属于同步代码,会被执行。如果让timer=setTimeout(()=>{});你会发现定时器有一个值,是一个数字。但是只是在执行完setTimeout之后才返回引用,剩下的倒计时和回调。都维护在定时器触发线程中。2、同理,上面的Promise.resolve()也是同步代码,令p=Promise.resolve()。会发现p是有值的,是一个Promise对象,只不过是执行完Promise.resolve()后返回引用而已。剩下的回调。它们都维护在微任务队列中。以上是我看了其他文章后的自己的想法,加上自己的理解和本地调试。如果有任何问题,请指正。
