在理解事件循环以前,我总会遇到一些奇奇怪怪的问题:好比明明已经调接口拿到了数据,但是跟在调数据以后的操做却没有正常执行;又或者不知道为啥,代码里非得加个setTimeout
才能正常跑通;特别是在运用Promise的时候,更是有各类问题百思不得解。赶上问题要解决,更要知道问题产生的缘由,这样才能hold住全场!前端
废话很少说了,先来看一段代码ajax
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的事件机制异步
咱们知道,js是单线程的,这就是说,只有一个主线程,主线程会自上而下依次执行调用栈中的事件。任务队列中的代码被加载到函数调用栈中去执行。当前的宏任务队列中的代码执行完毕后,会执行本次宏任务队列中分发到微任务队列中的代码。而后执行下一个宏任务队列中的代码,依次循环。函数
这里要提一点容易误解的地方,setTimeout
函数自己,实际上是当即执行的,它内部的任务,才会被分发到任务队列中延时执行。spa
setTimeout
的时候,新建了一个宏任务队列,函数内的任务被分发这个队列中等待执行Promise
,注意,Promise
中的第一个function中的代码会立马开始执行,遇到resolve
或者reject
后,then
方法中函数会被分发到本次事件循环的微任务队列中等待执行。因此这里立马打印出了'resolve'。遇到setTimeout2
后,一样新建了一个宏任务队列,其中的函数被分发到了这个新的宏任务队列中,then
方法中的操做被分发到了微任务队列中等待console
操做,因此并无再分发新的任务队列,可是因为第二个setTimeout
设定了200毫秒的延时,因此‘setTimeout2’被最后打印。说到这里,你基本上对事件循环有个大体的了解了。以前有个同窗问过我一个问题,点击轮播图下一页,可是页面没有反应,代码是这样的:线程
这个函数是点击下一页的按钮后轮播图转动,他在getNextPhoto
函数中调接口获取了下个页面的数据,goToPage
函数里是让轮播图切换的操做。相信若是你读懂了这篇文章,就会知道问题出在了哪里。显然获取数据ajax
是个异步操做,他被分发到了事件队列中等待执行,因此还没等数据回来,翻页的操做已经开始执行,因为没有数据,并无按预期效果显示。解决方法就是在getNextPhoto
函数里调接口拿到数据以后,再通知去执行goToPage
操做,问题就解决了。code
做为一个前端菜鸟,但愿获得各位大神的批评指正!server