当前位置: 首页 > Web前端 > HTML

好程序员web前端教程分享JavaScript的执行机制!

时间:2023-04-02 15:03:52 HTML

undefinedundefinedundefined一旦setInterval的回调函数fn的执行时间超过延迟时间ms,那么就根本没有时间间隔了。5.Promise和process.nextTick(callback)我们研究了传统的定时器,接下来我们来探究Promise和process.nextTick(callback)的性能。Promise的定义和作用本文不再赘述。不懂的读者可以向阮一峰老师学习Promise。而process.nextTick(callback)类似于node.js版本的“setTimeout”,在事件循环的下一个循环中调用callback回调函数。让我们进入正题。除了广义的同步任务和异步任务,我们还有更细化的任务定义:macro-task(宏任务):包括整体代码脚本、setTimeout、setIntervalmicro-task(微任务):Promise、Process.nextTick不同类型的任务会进入对应的EventQueue,比如setTimeout和setInterval会进入同一个EventQueue。事件循环的顺序决定了js代码的执行顺序。进入整体代码(宏任务)后,开始第一个循环。然后执行所有微任务。然后再从宏任务开始,找到其中一个要执行的任务队列,然后执行所有的微任务。听起来有点绕,那我们就用文章开头的代码来说明一下:1setTimeout(function(){2console.log('setTimeout');3})45newPromise(function(resolve){6console.log('promise');7}).then(function(){8console.log('then');9})1011console.log('console');·这段代码作为宏任务进入主线程。·第一次遇到setTimeout时,注册它的回调函数,分发到宏任务EventQueue中。(注册过程同上,下面不再赘述)·当接下来遇到一个Promise时,立即执行新的Promise,然后将then函数分发到microtaskEventQueue中。·遇到console.log()立即执行。·好了,整体代码脚本作为第一个宏任务执行,我们来看看都有哪些微任务?我们发现then是在microtaskEventQueue中执行的。·好了,第一轮事件循环结束,我们开始第二轮循环,当然是从宏任务EventQueue开始。我们在宏任务EventQueue中找到setTimeout对应的回调函数,立即执行。结束。事件循环、宏任务、微任务的关系如图所示:下面分析一段比较复杂的代码,看看你是否真的掌握了js的执行机制:1console.log('1');23setTimeout(function(){4console.log('2');5process.nextTick(function(){6console.log('3');7})8newPromise(function(resolve){9console.log('4');10resolve();11}).then(function(){12console.log('5')13})14})15process.nextTick(function(){16console.log('6');17})18newPromise(function(resolve){19console.log('7');20resolve();21}).then(function(){22console.log('8')23})2425setTimeout(function(){26console.log('9');27process.nextTick(function(){28console.log('10');29})30newPromise(function(resolve){31console.log('11');32resolve();33}).then(function(){34console.log('12')35})36})第一轮事件循环流程分析如下:一个宏task进入主线程,遇到console.log,输出1。·遇到setTimeout时,其回调function被分发到宏任务EventQueue。我们暂且记录为setTimeout1。·当遇到process.nextTick()时,将其回调函数分发到microtaskEventQueue。我们将其表示为process1。遇到Promise,直接执行新的Promise,输出7。然后分发到microtaskEventQueue。我们将其表示为then1。·我们又遇到了setTimeout,它的回调函数被分发到宏任务EventQueue中,我们记录为setTimeout2。MacrotaskEventQueueMicrotaskEventQueuesetTimeout1process1setTimeout2then1·上表显示了第一轮事件循环宏任务结束时各个EventQueue的状态。这时候1和7已经输出了。·我们发现了两个微任务,process1和then1。·执行process1,输出6。·执行then1,输出8。好了,第一轮事件循环正式结束,这一轮的结果是输出1,7,6,8。那么第二轮时间循环从setTimeout1宏任务开始:·首先输出2。接下来遇到process.nextTick(),同样分发到microtaskEventQueue,记录为process2。newPromise立即执行output4,然后也分发到microtaskEventQueue,记录为then2。MacrotaskEventQueueMicrotaskEventQueuesetTimeout2process2nullthen2·第二轮事件循环macrotask结束,我们发现有两个微任务process2和then2可以执行。·输出3.·输出5.·第二轮事件循环结束,第二轮输出2,4,3,5.·第三轮事件循环开始,此时只剩下setTimeout2,执行.·直接输出9。·分发process.nextTick()到微任务事件队列。将其表示为process3。·直接执行newPromise,输出11。·将then分发到微任务EventQueue,记为then3。MacrotaskEventQueueMicrotaskEventQueuenullprocess3nullthen3·第三轮事件循环macrotask执行结束,执行process3和then3两个microtask。·输出10。·输出12。第三轮事件循环结束,第三轮输出9、11、10、12。整个代码,一共三个事件循环,完整输出为1、7、6、8、2、4、3,5,9,11,10,12.(注意node环境下的事件监听依赖libuv和前端环境不完全一样,输出顺序可能有错误)6.写在最后(1)js异步我们一开始就说javascript是单线程语言,不管新框架新语法糖实现了什么样的所谓异步,其实都是通过同步方式模拟出来的。牢牢抓住单线程非常重要。(2)事件循环EventLoop事件循环是js实现异步的一种方法,也是js的执行机制。(3)javascript的执行和运行有很大的区别。JavaScript在不同的环境下执行,比如node、browser、Ringo等,执行方式不同。操作多参考javascript解析引擎,统一。(4)setImmediate微任务和宏任务的种类很多,比如setImmediate等,它们在执行上都有相似之处。感兴趣的同学可以自行学习。(5)最后javascript是单线程语言。EventLoop是javascript的执行机制。牢牢抓住两个基本点,专注于认真学习javascript,早日实现成为前端高手的伟大梦想!