JavaScript事件执行机制
因为javascript是一门单线程语言,所以我们可以得出结论:javascript是按照语句出现的顺序执行的。javascript每执行一个语句,我们称之为一次任务,因此可以将任务分为两类:同步任务和异步任务,先来看下面这张图:
同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数。
当指定的事情完成时,Event Table会将这个函数移入Event Queue(事件队列)。
主线程内的任务执行完毕为空,会去读取Event Queue(事件队列)中对应的函数,进入主线程执行。
上述过程会不断重复,也就是常说的Event Loop(事件循环)。
只看导图可能有些笼统,请结合下面这段代码:
console.log(1) // 同步 setTimeout(() => { console.log(2) // 异步,注册回调函数fn1 }, 2000);console.log(3) // 同步 setTimeout(() => { console.log(4) // 异步,注册回调函数fn2 }, 0); console.log(5) // 同步
console.log(1)是一条同步任务,进入主线程;setTimeout(() => {console.log(2)}, 2000);是一条异步任务,进入Event Table,注册回调函数fn1;console.log(3)是一条同步任务,进入主线程;setTimeout(() => {console.log(4)}, 0);是一条异步任务,进入Event Table,注册回调函数fn2;console.log(5)是一条同步任务,进入主线程。
由于setTimeout把回调函数fn2的延时设置为0,所以注册完回调函数后,Event Table会将立即将fn2移入Event Queue(事件队列);同理2s后Event Table将fn1移入Event Queue。这些操作进入队列的顺序,由设定的延迟时间来决定。
所以主线程第一次执行完成后输出结果1、3、5,此时主线程内的任务为空,会去顺序读取Event Queue(事件队列)中的函数,所以主线程第二次执行完成后输出结果1、3、5、4。
只要主线程的任务变为空,就回去Event Queue(事件队列)询问是否有可自行的回调函数,这时发现Event Queue(事件队列)中还有回调函数fn1,所以fn1会进入主线程执行,所以主线程第三次执行完成后输出结果1、3、5、4、2。
到此,整个js事件执行结束。
前面说了,等所有同步代码都执行完,再从Event Queue(事件队列)里依次执行所有异步回调函数,实际上Event Queue(事件队列)也有自己的规则:Event Queue(事件队列)用来存异步回调,而异步任务分为宏任务和微任务,并且微任务执行时机先于宏任务
macro-task(宏任务):包括整体代码script,setTimeout,setInterval
micro-task(微任务):Promise,process.nextTick
整体代码是一个宏任务,进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务,如下图所示:
setTimeout(function() { console.log('setTimeout'); // 异步:宏任务 }) new Promise(function(resolve) { console.log('promise'); // 同步 resolve(); }).then(function() { console.log('then'); // 异步:微任务 }) console.log('console'); // 同步
这段代码作为第一个宏任务,进入主线程,先遇到setTimeout,setTimeout异步执行,将其回调函数注册后分发到宏任务Event Queue。
接下来遇到了Promise,new Promise立即执行,输出promise,then函数分发到微任务Event Queue。
在往后遇到console.log(),立即执行,输出console。
整体代码script作为第一个宏任务执行结束,输出结果promise console,Event Queue里面有微任务then在和宏任务setTimeout。
执行微任务then,第一轮事件循环正式结束,这一轮的结果是输出promise console then。那么第二轮时间循环从setTimeout1宏任务开始。
立即执行宏任务Event Queue中setTimeout对应的回调函数,回调函数中只有一个console.log(),执行完第二轮事件循环结束,输出promise console then setTimeout。
总结:
javascript是一门单线程语言
事件轮询(Event Loop)是js实现异步的一种方法,也是js的执行机制
本站部分文章、数据、素材收集于网络,所有版权均归源网站或原作者所有!
如果侵犯了您的权益,请来信告知我们下线删除,邮箱:357234902@qq.com
上一篇:jq实现图片点击放大(预览)效果
下一篇:js作用域、作用域链、闭包