关于事件循环这个问题,前前后后阅读过不下十篇文章,每看过一篇之后就觉得自己明白了其中的道理,然而在每次遇到问题之后才发现其实还是不懂,最近在开发的过程中就遇到同样让我头疼的问题,查阅资料后才明白,所以在这里记录一下。
问题的起因 ** 开发的过程中遇到这么一个问题,页面加载的时候我要先请求一个接口,然后在接口回调成功之后我需要执行一个事件,由于一些特殊的原因这个执行的事件没法写在ajax的success回调中,所以我就想到把这个事件放到settimeout中,凭借我之前对事件循环的理解,http请求和settimeout都是异步请求,都维护在事件队列中,我先写http请求再写settimeout,那么settimeout中的事件肯定在http请求完成后执行。
事实证明还是我太年轻,测试结果发现基本每次都是先执行settimeout中的事件,然后才执行http回调。 开始很不解,就模拟了一下,代码如下:
$.ajax({
url: 'xxxx/monitor/presto/cluster/sysInfo',
type: 'post',
data: JSON.stringify({
cluster: 2,
end: "2019-08-28 13:17:13",
ip: "192.168.25.118",
start: "2019-08-28 12:47:13"
}),
contentType: "application/jsson; charset=utf-8",
dataType: "json",
success: function() {
console.log('success')
}
})
setTimeout(() => {
console.log('settimeout')
})
// settimeout success
以我之前的理解,在这里我是很不解的,然后查询了一些资料,最后在知乎的一篇文章中看到了一段描述才让我豁然开朗,原文如下:
js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列**。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码...,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。** ** 这里和我之前理解偏差在于:
js引擎在遇到异步任务后会将这个事件挂起,等待有返回结果后才放到事件队列,主线程空闲时会查找队列中是否有任务,也就是说这些异步任务,谁先执行完成谁就先被放到任务队列,按照这个顺序在主线程中执行。 而不是直接将事件放到队列中,等待主线程空闲之后,按照顺序将事件队列中的异步任务放到主线程,再执行再返回结果。
结论
所以在这里我就明白上面的输出原因,http请求的响应时间稍有些延迟,在成功回调之前settimeout已经执行完成,所以settimeout在ajax之前被放入事件队列中,所以肯定是先执行settimeout再执行success
参考知乎原文:链接