摘要:由于两个都是异步函数,按照执行顺序,先将放到,接着将移到,因为在指定要秒后才执行,所以先于到注册回调函数到,所以输出的结果是。
众所周知,Javascript是单线程语言, 这就意味着,所有的任务都必须按照顺序执行,只有等前面的一个任务执行完毕了,下一个任务才能执行。如果前面一个任务耗时很长,后一个任务就得一直等着,因此,为了实现主线程的不阻塞,就有了Event Loop。
1、javascript事件循环首先,我们先了解一下同步任务和异步任务,同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
为了更好的了解执行机制,看下图
以上图说明主线程在执行的时候产生堆(内存分配)和堆栈(执行上下文),JavaScript是单线程的,意味着当执行环境的堆栈中的一个任务(task)在执行的时候,其它的任务都要处于等待状态。当主进程执行到异步操作的时候就会将异步操作对应的task放到event table,指定的事情完成时,Event Table会将这个函数移入Event Queue。主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行,因为这个过程是不断重复的,所以称为Event Loop(事件循环),接下来,我们用几个例子进行分析
eg1:
console.log(1); setTimeout(function () { console.log(2); }) console.log(3); //执行结果:1、3、2
我们来分析一下这段代码,首先,根据执行上下文可知,执行环境栈中就有了一个task——console.log(1),输出1。接着往下执行,因为setTimeout是异步函数,所以将setTimeout进入event table,注册了一个回调函数在event queue,我们暂且称为fun1,此时的流程如下图:
接着往下执行,执行环境栈中会创建一个console.log(3)的task,并执行它,输出3,此时,执行环境已经没有任务了,则去Event Queue读取对应的函数,fun1被发现,进入主线程输出2,整个过程已经完成,所以输出的结果是1、3、2。
eg2:
setTimeout(function () { console.log(1) }, 3) setTimeout(function () { console.log(2) }) 输出2,1
我们再来简单的分析一下这个列子,我们暂且称第一个setTimeout为Time1,第二个为Time2。由于两个都是异步函数,按照执行顺序,先将Time放到event Table,接着将Time移到event Table,因为Time在event Table指定要3秒后才执行,所以Time2先于Time1到注册回调函数到event queue,所以输出的结果是2,1。
2、macro-task(宏任务)、micro-task(微任务)MacroTask: script(整体代码), setTimeout, setInterval, setImmediate(node独有), I/O, UI rendering MicroTask: process.nextTick(node独有), Promises, Object.observe(废弃), MutationObserver
任务又分为宏任务和微任务两种,在同一个上下文中,总的执行顺序为“同步代码—>microTask—>macroTask”,根据上面event loop的流程图,我们用列子来做进一步的了解:
eg1:
setTimeout(function () { console.log(1); },0); console.log(2); process.nextTick(() => { console.log(3); }); new Promise(function (resolve, rejected) { console.log(4); resolve() }).then(res=>{ console.log(5); }) setImmediate(function () { console.log(6) }) console.log("end"); //输出2、4、end、3、5、1、6
本例参考《JavaScript中的执行机制》,里面有详细的解释,大家可以参考下。
3、优先级我们将上面的例子稍微改一下,将process.nextTick移到promise的后面,看下面的代码:
setTimeout(function () { console.log(1); },0); console.log(2); new Promise(function (resolve, rejected) { console.log(4); resolve() }).then(res=>{ console.log(5); }) process.nextTick(() => { console.log(3); }); setImmediate(function () { console.log(6) }) console.log("end");
按照前面的分析,先执行同步代码,先输出“2,4,end”;然后是微任务promise输出5,process.nextTick输出3;最后的宏任务输出1,6。所以结果为2,4,end,5,3,1,6,然后事实并非如此,结果还是输出2、4、end、3、5、1、6,这是因为process.nextTick注册的函数优先级高于Promise**。
关于Event Loop的其他特殊情况,大家可参考文章一篇文章教会你Event loop——浏览器和Node和Event Loop的规范和实现,里面有更详细的介绍。
console.log(1) setTimeout(() => { console.log(2) new Promise(resolve => { console.log(4) resolve() }).then(() => { console.log(5) }) setTimeout(() => { console.log(999) }) }) new Promise(resolve => { console.log(7) resolve() }).then(() => { console.log(8) }) setTimeout(() => { console.log(9) new Promise(resolve => { console.log(11) resolve() }).then(() => { console.log(12) }) })
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/102381.html
摘要:主线程在任务队列中读取事件,这个过程是循环不断地,所以这种运行机制叫做事件循环是在执行栈同步代码结束之后,下一次任务队列执行之前。 单线程 javascript为什么是单线程语言,原因在于如果是多线程,当一个线程对DOM节点做添加内容操作的时候,另一个线程要删除这个DOM节点,这个时候,浏览器应该怎么选择,这就造成了混乱,为了解决这类问题,在一开始的时候,javascript就采用单线...
摘要:如果当前没有事件也没有定时器事件,则返回。相关资料关于的架构及设计思路的事件讨论了使用线程池异步运行代码。下一篇初窥事件机制的实现二中定时器的实现 在浏览器中,事件作为一个极为重要的机制,给予JavaScript响应用户操作与DOM变化的能力;在Node.js中,事件驱动模型则是其高并发能力的基础。 学习JavaScript也需要了解它的运行平台,为了更好的理解JavaScript的事...
摘要:浏览器与的异同,以及部分机制有人对部分迷惑,本身构造函数是同步的,是异步。浏览器的的已全部分析完成,过程中引用阮一峰博客,知乎,部分文章内容,侵删。 浏览器与NodeJS的EventLoop异同,以及部分机制 PS:有人对promise部分迷惑,Promise本身构造函数是同步的,.then是异步。---- 2018/7/6 22:35修改 javascript 是一门单线程的脚本...
摘要:前言前几天在理解的事件环机制中引发了我对浏览器里的好奇。接下来理解浏览器中的,先看一张图堆和栈堆是用户主动请求而划分出来的内存区域,比如你,就是将一个对象存入堆中,可以理解为存对象。废话不多说,直接上图个人理解。参考资料运行机制详解再谈 前言 前几天在理解node的事件环机制中引发了我对浏览器里Event Loop的好奇。我们都知道javascript是单线程的,任务是需要一个一个按顺...
阅读 2484·2021-09-02 15:40
阅读 1545·2019-08-30 15:54
阅读 1064·2019-08-30 12:48
阅读 3357·2019-08-29 17:23
阅读 1033·2019-08-28 18:04
阅读 3636·2019-08-26 13:54
阅读 587·2019-08-26 11:40
阅读 2374·2019-08-26 10:15