当前位置: 首页 > 后端技术 > Node.js

js运行机制与异步编程(二)

时间:2023-04-03 18:07:42 Node.js

上一篇主要梳理了js引擎的工作原理。这篇文章主要梳理了js的事件循环和异步编程的原理。提到js是单线程的,而浏览器渲染核心包含多线程,与js代码部分相关的线程有:js引擎线程处理ajax请求线程,线程处理DOM事件,定时器,读取线程以及写文件(Node.JS)等。因为JS是单线程的,这是从JS引擎的角度来说的。所谓单线程,就是在JS引擎中只有一个线程负责解释执行JS代码。:主线程。js分为同步任务和异步任务。同步任务在主线程上执行,形成一个执行栈。在主线程之外,事件触发线程管理着一个任务队列。只要异步任务有运行结果,就会在任务队列中。在中放置一个事件。一旦执行栈中的所有同步任务执行完毕(此时js引擎空闲),系统会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行。JS的执行机制是一个主线程+一个任务队列。同步任务是在主线程上执行的任务,异步任务是放在任务队列中的任务。所有的同步任务都在主线程中执行,主线程构成一个执行栈。异步任务在有运行结果时,会在任务队列中放入一个事件,比如计时2秒,2秒后放入任务队列(callbackputTaskqueue,不是setTimeout函数入队列).EventLoop-脚本运行时,首先依次运行执行栈,然后从队列中提取事件运行任务队列中的任务。这个过程不断重复。所以称为事件循环(EventLoop)。Macrotask和microtask上面的js运行机制主要讲解了es5,es6的出现和普及,还有一个新的概念,promise,它的出现,更进一步,JS分为两种任务:macrotask和microtask,在ECMAScript中,微任务称为作业,宏任务可以称为任务。什么样的场景会形成macrotask和microtask?macrotask:主代码块,setTimeout,setInterval,setImmediate,I/O,UI渲染。等等(可以看到,事件队列中的每个事件都是一个宏任务)微任务:process.nextTick、Promise(native)、Object。观察,node环境下的MutationObserver,process.nextTick的优先级高于Promise,即可以简单理解为:宏任务结束后,会先执行微任务队列中的nextTickQueue部分,然后执行部分微任务中的Promise。总结一下运行机制:执行一个宏任务(不在栈中就从事件队列中获取)。如果在执行过程中遇到微任务,则将其添加到微任务的任务队列中。宏任务执行完毕后,立即执行当前微任务。任务队列中的所有microtasks(顺序执行)当前macrotask执行完毕,开始检查渲染,然后GUI线程接管渲染渲染完成后,JS线程继续接管并开始下一个macrotask(从事件队列中获取)案例说明案例一:setImmediate(function(){console.log(1);},0);setTimeout(function(){console.log(2);},0);newPromise(function(resolve){console.log(3);resolve();console.log(4);}).then(function(){console.log(5);});console.log(6);process.nextTick(function(){console.log(7);});console.log(8);根据js的运行原理解释一下上面代码的执行顺序:第一步是执行整体代码的脚本,执行过程是createsetImmediatemacro-taskcreatesetTimeoutmacro-taskcreate微任务Promise.then的回调,执行脚本console.log(3);解决();控制台日志(4);此时输出3和4,虽然调用并执行了resolve,但是整体代码还没有执行完,无法进入Promise.then流程。console.log(6)output6process.nextTickcreatemicro-taskconsole.log(8)output8经过第一次处理,已经输出了3468第二步是因为其他微任务的优先级高于宏任务.此时微任务中有两个优先级process.nextTick高于Promise的任务。所以先输出7,再输出5。Step3微任务任务列表已经执行完毕,回家执行宏任务。由于setTimeout的优先级高于setIImmediate,所以先输出2,再输出1。参考:https://blog.csdn.net/gy_u_yg...https://blog.csdn.net/m0_3775...