摘要:任务队列中的代码被加载到函数调用栈中去执行。说到这里,你基本上对事件循环有个大致的了解了。
在理解事件循环之前,我总会遇到一些奇奇怪怪的问题:比如明明已经调接口拿到了数据,可是跟在调数据之后的操作却没有正常执行;又或者不知道为啥,代码里非得加个setTimeout才能正常跑通;特别是在运用Promise的时候,更是有各种问题百思不得解。遇上问题要解决,更要知道问题产生的原因,这样才能hold住全场!
废话不多说了,先来看一段代码
console.log("start"); setTimeout(function(){ console.log("setTImeout1") },0); new Promise(function(resolve,reject){ console.log("resolve") setTimeout(function(){ console.log("setTimeout2") },200); resolve() }).then(function(){ console.log("then") }); setTimeout(function(){ console.log("setTimeout3") },0); console.log("end");
结果是start resolve end then setTimeout1 setTimeout3 settimeout2。
在分析结果之前,我先来科普几个概念,这些概念的表述不一定与标准完全对应,但是可以帮助你更容易理解JS的事件机制
宏任务(macro-task):包括js整体代码,setTimeout,setInterval,setImmediate ,I/O, UI renderder等
微任务(micro-task):包括Promise,Object.observe,process.nextTick,MutationObserver等
调用栈:js被加载进来之后,会从上至下读取代码,同步代码被立即执行,而异步代码被加入事件队列中
事件队列:一些没有被立即执行的代码被添加到事件队列中,队列是一种先进先出的数据结构,也就是说,先加入事件队列的任务会被优先执行
我们知道,js是单线程的,这就是说,只有一个主线程,主线程会自上而下依次执行调用栈中的事件。任务队列中的代码被加载到函数调用栈中去执行。当前的宏任务队列中的代码执行完毕后,会执行本次宏任务队列中分发到微任务队列中的代码。然后执行下一个宏任务队列中的代码,依次循环。
这里要提一点容易误解的地方,setTimeout函数本身,其实是立即执行的,它内部的任务,才会被分发到任务队列中延时执行。
代码被加载后,全局上下文进入函数调用栈,紧接着,‘start’被执行
遇到setTimeout的时候,新建了一个宏任务队列,函数内的任务被分发这个队列中等待执行
此时遇到了Promise,注意,Promise中的第一个function中的代码会立马开始执行,遇到resolve或者reject后,then方法中函数会被分发到本次事件循环的微任务队列中等待执行。所以这里立马打印出了"resolve"。遇到setTimeout2后,同样新建了一个宏任务队列,其中的函数被分发到了这个新的宏任务队列中,then方法中的操作被分发到了微任务队列中等待
代码继续往下,遇到"setTimeout3"后再次新建了一个新的宏任务队列
"end"被立即执行。此时有三个宏任务队列,一个微任务队列
微任务队列中的操作被执行,也就是打印出了‘then’,此时,第一轮的事件循环结束。
第一轮的事件循环结束,开始下一轮的事件循环,依次执行每个宏任务队列中的内容,我们这里宏任务队列中的函数比较简单,都是console操作,所以并没有再分发新的任务队列,但是由于第二个setTimeout设定了200毫秒的延时,所以‘setTimeout2’被最后打印。
说到这里,你基本上对事件循环有个大致的了解了。之前有个同学问过我一个问题,点击轮播图下一页,但是页面没有反应,代码是这样的:
这个函数是点击下一页的按钮后轮播图转动,他在getNextPhoto函数中调接口获取了下个页面的数据,goToPage函数里是让轮播图切换的操作。相信如果你读懂了这篇文章,就会知道问题出在了哪里。显然获取数据ajax是个异步操作,他被分发到了事件队列中等待执行,所以还没等数据回来,翻页的操作已经开始执行,由于没有数据,并没有按预期效果显示。解决方法就是在getNextPhoto函数里调接口拿到数据之后,再通知去执行goToPage操作,问题就解决了。
作为一个前端菜鸟,希望得到各位大神的批评指正!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/107961.html
摘要:事件完成,回调函数进入。我们来分析一段较复杂的代码,看看你是否真的掌握了的执行机制第一轮事件循环流程分析如下整体作为第一个宏任务进入主线程,遇到,输出。宏任务微任务第三轮事件循环宏任务执行结束,执行两个微任务和。 关于JavaScript 首先js是单线程的,执行任务肯定是一个接着一个。在最新的html5中提出了web-worker,但是JavaScript是单线程这一核心没有改变,一...
摘要:关于这部分有严格的文字定义,但本文的目的是用最小的学习成本彻底弄懂执行机制,所以同步和异步任务分别进入不同的执行场所,同步的进入主线程,异步的进入并注册函数。宏任务微任务第三轮事件循环宏任务执行结束,执行两个微任务和。 不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作,我们经常会遇到这样的情况:给定的几行代码,我们需要知道其输出内容和顺序。 因为javascr...
摘要:事件完成,回调函数进入。主线程从读取回调函数并执行。终于执行完了,终于从进入了主线程执行。遇到,立即执行。宏任务微任务第三轮事件循环宏任务执行结束,执行两个微任务和。事件循环事件循环是实现异步的一种方法,也是的执行机制。 本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我。不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作...
js运行机制-事件循环EventLoop 先来看看一段js代码: console.log(script begin) setTimeout(() => { console.log(setTimeout) },0) new Promise((resolve) => { console.log(promise begin) for(let i = 0; i < 1000; i...
阅读 1161·2021-10-11 10:59
阅读 1952·2021-09-29 09:44
阅读 837·2021-09-01 10:32
阅读 1409·2019-08-30 14:21
阅读 1847·2019-08-29 15:39
阅读 2959·2019-08-29 13:45
阅读 3514·2019-08-29 13:27
阅读 1985·2019-08-29 12:27