JavaScript单线程出身:JavaScript是一种浏览器脚本语言。JavaScript的主要目的是与用户交互和操作DOM。为了避免复杂性,JavaScript从诞生之日起就是单线程的。语言。例如,假设JavaScript同时有两个线程,一个线程向某个DOM节点添加内容,另一个线程删除这个节点,那么浏览器应该以哪个线程为基础呢?因此,为了避免复杂性,JavaScript从一开始就是单线程的。单线程及存在的问题:单线程意味着所有的任务都需要排队,只有上一个任务完成后才会执行下一个任务。如果前一个任务耗时很长,后一个任务就得一直等下去。问题解决--synchronous、asynchronoussynchronous(同步任务)和asynchronousk(异步任务)。一个任务;异步任务是不能立即得到结果,需要额外操作才能得到结果的任务。异步任务不进入主线程而是进入“任务队列”(taskqueue)任务,只有“任务队列”通知主线程,当一个异步任务可以执行时,任务才会进入主线程执行.macro-task(宏任务)和micro-task(微任务)macro-task:macro-task可以理解为执行栈每次执行的代码都是宏任务(包括每次从事件中获取事件回调)queue并放入执行栈中的Execution,每个宏任务都会从头到尾执行这个任务,不会执行其他的)包括整体代码脚本、setTimeout、setInterval等微任务:微任务可以理解为当前任务执行结束后立即执行任务包括Promise、process.nextTick等。单线程。实际上,宏任务队列和微任务队列的执行都是事件循环的一部分。事件循环的具体过程如下:从宏任务队列中,按照入队顺序,找到第一个要执行的宏任务,放入调用栈,开始执行;执行完宏任务下的所有同步任务后,清空调用栈,最后将宏任务压出宏任务队列,然后微任务队列开始按照入队顺序依次执行微任务,直到微任务队列被清空;当微任务队列清空时,事件循环结束;然后从宏任务的任务队列中,找到下一个要执行的宏任务,开始第二次事件循环,直到宏任务队列清空。js执行机制流程图注意:当我们第一次执行时,解释器会将整体代码脚本放入宏任务队列中,所以事件循环从第一个宏任务开始;所以我在流程图中把主线程单独分开了。如果在microtask执行过程中有新的microtask产生并加入到microtask队列中,也需要一并清除;在微任务队列被清除之前,下一个宏任务不会被执行。流程图解释:Js任务入栈后,判断是否为同步任务,立即执行同步任务;如果是异步任务,则判断将microtask或macrotask加入到对应的队列中进行处理。所有同步进程执行完毕后,立即执行当前microtask队列中的所有microtask(因为整体的Js代码被看做一个macrotask)。当微任务被清除时,执行宏任务队列中的下一个宏任务。执行完成后判断微任务队列中是否有微任务,如果有则清空微任务队列,开始下一个循环。EventLoop实践console.log("a");setTimeout(function(){console.log("b");},0);newPromise((resolve)=>{console.log("c");resolve();}).then(function(){console.log("d");}).then(function(){console.log("e");});console.log("f");/***输出:acfdeb*/asyncfunctionasync1(){console.log("a");constres=awaitasync2();console.log("b");}asyncfunctionasync2(){console.log("c");返回2;}console.log("d");setTimeout(()=>{console.log("e");},0);async1().then(res=>{console.log("f")})newPromise((resolve)=>{console.log("g");resolve();}).then(()=>{console.log("h");});控制台。log("i");/***output:dacgibhfe*/这段代码声明了两个异步方法,在整体的Script语句中,第一个output:d;setTimeout中的语句加入宏任务队列;宏任务队列和微任务队列的整体ScriptsetTimeoutasync1()被执行,输出:a;async2()执行后,输出:c;等待块执行;console.log("b")暂时不执行,而是执行主线程任务;此时async1()还没有执行完,不会将.then()方法加入到microtask队列中;宏任务队列和微任务队列的整体ScriptsetTimeout执行新的Promise输出:g;.then(()=>{console.log("h");})进入微任务队列;脚本console.log("h")在宏任务队列中将微任务队列作为一个整体设置超时6.执行console.log("i");语句,输出:i;此时主线程的同步任务已经全部执行完毕,执行完毕,返回block继续执行;输出:b;.then(res=>{console.log("f")})加入微队列;宏任务队列微任务队列setTimeoutconsole.log("h")console.log("f")7.清空microtask队列后,执行macrotask队列中的下一个任务,开始下一个循环;输出h,f,e;console.log('1');setTimeout(function(){console.log('2');process.nextTick(function(){console.log('3');})newPromise(function(resolve){console.log('4');resolve();}).then(function(){console.log('5')})})process.nextTick(function(){console.log('6');})newPromise(function(resolve){console.log('7');resolve();}).then(function(){console.log('8')})setTimeout(function(){console.log('9');process.nextTick(function(){console.l奥格('10');})newPromise(function(resolve){console.log('11');resolve();}).then(function(){console.log('12')})})/***输出:1,7,6,8,2,4,3,5,9,11,10,12(node和浏览器可能略有不同)*/注意:在node中,进程.nextTick()的优先级高于Promise.then、catch、finally;在node中,宏任务队列:setImmediate()队列的优先级高于setTimeout()队列;node14之后,每执行一次宏任务,就清空实时微任务队列参考文档:做点动画,这次学习一下EventLoop,彻底理解JavaScript执行机制深入分析EventLoop和浏览器渲染,帧动画,还有你不知道的空闲回调(动画演示
