js的settimeout方法 settimeout函数用法( 二 )


定时器线程前面异步例子的setTimeout其实就运行在这里,他跟JS主线程根本不在同一个地方,所以“单线程的JS”能够实现异步 。JS的定时器方法还有setInterval,也是在这个线程 。
事件触发线程定时器线程其实只是一个计时的作用,他并不会真正执行时间到了的回调,真正执行这个回调的还是JS主线程 。所以当时间到了定时器线程会将这个回调事件给到事件触发线程,然后事件触发线程将它加到事件队列里面去 。最终JS主线程从事件队列取出这个回调执行 。事件触发线程不仅会将定时器事件放入任务队列,其他满足条件的事件也是他负责放进任务队列 。
异步HTTP请求线程这个线程负责处理异步的ajax请求,当请求完成后,他也会通知事件触发线程,然后事件触发线程将这个事件放入事件队列给主线程执行 。
所以JS异步的实现靠的就是浏览器的多线程,当他遇到异步API时,就将这个任务交给对应的线程,当这个异步API满足回调条件时,对应的线程又通过事件触发线程将这个事件放入任务队列,然后主线程从任务队列取出事件继续执行 。这个流程我们多次提到了任务队列,这其实就是Event Loop,下面我们详细来讲解下 。
Event Loop所谓Event Loop,就是事件循环,其实就是JS管理事件执行的一个流程,具体的管理办法由他具体的运行环境确定 。目前JS的主要运行环境有两个,浏览器和Node.js 。这两个环境的Event Loop还有点区别,我们会分开来讲 。
浏览器的Event Loop事件循环就是一个循环,是各个异步线程用来通讯和协同执行的机制 。各个线程为了交换消息,还有一个公用的数据区,这就是事件队列 。各个异步线程执行完后,通过事件触发线程将回调事件放到事件队列,主线程每次干完手上的活儿就来看看这个队列有没有新活儿,有的话就取出来执行 。画成一个流程图就是这样:
流程讲解如下:
主线程每次执行时,先看看要执行的是同步任务,还是异步的API同步任务就继续执行,一直执行完遇到异步API就将它交给对应的异步线程,自己继续执行同步任务异步线程执行异步API,执行完后,将异步回调事件放入事件队列上主线程手上的同步任务干完后就来事件队列看看有没有任务主线程发现事件队列有任务,就取出里面的任务执行主线程不断循环上述流程
定时器不准Event Loop的这个流程里面其实还是隐藏了一些坑的,最典型的问题就是总是先执行同步任务,然后再执行事件队列里面的回调 。这个特性就直接影响了定时器的执行,我们想想我们开始那个2秒定时器的执行流程:
主线程执行同步代码遇到setTimeout,将它交给定时器线程定时器线程开始计时,2秒到了通知事件触发线程事件触发线程将定时器回调放入事件队列,异步流程到此结束主线程如果有空,将定时器回调拿出来执行,如果没空这个回调就一直放在队列里 。
上述流程我们可以看出,如果主线程长时间被阻塞,定时器回调就没机会执行,即使执行了,那时间也不准了,我们将开头那两个例子结合起来就可以看出这个效果:
const syncFunc = (startTime) => {const time = new Date().getTime();while(true) {if(new Date().getTime() - time > 5000) {break;}}const offset = new Date().getTime() - startTime;console.log(`syncFunc run, time offset: ${offset}`);}const asyncFunc = (startTime) => {setTimeout(() => {const offset = new Date().getTime() - startTime;console.log(`asyncFunc run, time offset: ${offset}`);}, 2000);}const startTime = new Date().getTime();asyncFunc(startTime);syncFunc(startTime);执行结果如下:


以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!

「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助: