settimeout函数用法「附:js的settimeout方法」

小伙伴们大家好,今天杨偲眙讲的文章是settimeout函数用法,js的settimeout方法,还有关于队列,任务,定时器这些的精品干货文章,这些其实都是一些必备知识,只是有些时候我们没有遇到就没有去了解而已!

笔者以前面试的时候经常遇到写一堆setTimeout,setImmediate来问哪个先执行。本文主要就是来讲这个问题的,但是不是简单的讲讲哪个先,哪个后。笼统的知道setImmediate比setTimeout(fn, 0)先执行是不够的,因为有些情况下setTimeout(fn, 0)是会比setImmediate先执行的。要彻底搞明白这个问题,我们需要系统的学习JS的异步机制和底层原理。本文就会从异步基本概念出发,一直讲到Event Loop的底层原理,让你彻底搞懂setTimeout,setImmediate,Promise, process.nextTick谁先谁后这一类问题。

同步和异步

同步异步简单理解就是,同步的代码都是按照书写顺序执行的,异步的代码可能跟书写顺序不一样,写在后面的可能先执行。下面来看个例子:

const syncFunc = () => {  const time = new Date().getTime();  while(true) {    if(new Date().getTime() - time > 2000) {      break;    }  }  console.log(2);}console.log(1);syncFunc();console.log(3);

上述代码会先打印出1,然后调用syncFunc,syncFunc里面while循环会运行2秒,然后打印出2,最后打印出3。所以这里代码的执行顺序跟我们的书写顺序是一致,他是同步代码:

settimeout函数用法,js的settimeout方法,队列,任务,定时器

可以看到我们中间调用的asyncFunc里面的2却是最后输出的,这是因为setTimeout是一个异步方法。他的作用是设置一个定时器,等定时器时间到了再执行回调里面的代码。所以异步就相当于做一件事,但是并不是马上做,而是你先给别人打了个招呼,说xxx条件满足的时候就干什么什么。就像你晚上睡觉前在手机上设置了一个第二天早上7天的闹钟,就相当于给了手机一个异步事件,触发条件是时间到达早上7点。使用异步的好处是你只需要设置好异步的触发条件就可以去干别的事情了,所以异步不会阻塞主干上事件的执行。特别是对于JS这种只有一个线程的语言,如果都像我们第一个例子那样去while(true),那浏览器就只有一直卡死了,只有等这个循环运行完才会有响应。

JS异步是怎么实现的

我们都知道JS是单线程的,那单线程是怎么实现异步的呢?事实上所谓的”JS是单线程的”只是指JS的主运行线程只有一个,而不是整个运行环境都是单线程。JS的运行环境主要是浏览器,以大家都很熟悉的Chrome的内核为例,他不仅是多线程的,而且是多进程的:

settimeout函数用法,js的settimeout方法,队列,任务,定时器

流程讲解如下:

主线程每次执行时,先看看要执行的是同步任务,还是异步的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);

执行结果如下:

settimeout函数用法,js的settimeout方法,队列,任务,定时器

上图需要注意以下几点:

一个Event Loop可以有一个或多个事件队列,但是只有一个微任务队列。微任务队列全部执行完会重新渲染一次每个宏任务执行完都会重新渲染一次requestAnimationFrame处于渲染阶段,不在微任务队列,也不在宏任务队列

所以想要知道一个异步API在哪个阶段执行,我们得知道他是宏任务还是微任务。

常见宏任务有:

script (可以理解为外层同步代码)setTimeout/setIntervalsetImmediate(Node.js)I/OUI事件postMessage

常见微任务有:

Promiseprocess.nextTick(Node.js)Object.observeMutaionObserver

上面这些事件类型中要注意Promise,他是微任务,也就是说他会在定时器前面运行,我们来看个例子:

console.log('1');setTimeout(() => {  console.log('2');},0);Promise.resolve().then(() => {  console.log('5');})new Promise((resolve) => {  console.log('3');  resolve();}).then(() => {  console.log('4');})

上述代码的输出是1,3,5,4,2。因为:

先输出1,这个没什么说的,同步代码最先执行console.log(‘2’);在setTimeout里面,setTimeout是宏任务,“2”进入宏任务队列console.log(‘5’);在Promise.then里面,进入微任务队列console.log(‘3’);在Promise构造函数的参数里面,这其实是同步代码,直接输出console.log(‘4’);在then里面,他会进入微任务队列,检查事件队列时先执行微任务同步代码运行结果是“1,3”然后检查微任务队列,输出“5,4”最后执行宏任务队列,输出“2”

Node.js的Event Loop

Node.js是运行在服务端的js,虽然他也用到了V8引擎,但是他的服务目的和环境不同,导致了他API与原生JS有些区别,他的Event Loop还要处理一些I/O,比如新的网络连接等,所以与浏览器Event Loop也是不一样的。Node的Event Loop是分阶段的,如下图所示:

settimeout函数用法,js的settimeout方法,队列,任务,定时器

上面的这个流程说简单点就是在一个异步流程里,setImmediate会比定时器先执行,我们写点代码来试试:

console.log('outer');setTimeout(() => {  setTimeout(() => {    console.log('setTimeout');  }, 0);  setImmediate(() => {    console.log('setImmediate');  });}, 0);

上述代码运行如下:

settimeout函数用法,js的settimeout方法,队列,任务,定时器

好像是setTimeout先输出来,我们多运行几次看看:

settimeout函数用法,js的settimeout方法,队列,任务,定时器

我们还是来理一下流程:

我们代码基本都在readFile回调里面,他自己执行时,已经在poll阶段遇到setTimeout(fn, 0),其实是setTimeout(fn, 1),塞入后面的timers阶段遇到setImmediate,塞入后面的check阶段遇到nextTick,立马执行,输出’nextTick 1’到了check阶段,输出’setImmediate’,又遇到个nextTick,立马输出’nextTick 2’到了下个timers阶段,输出’setTimeout’

这种机制其实类似于我们前面讲的微任务,但是并不完全一样,比如同时有nextTick和Promise的时候,肯定是nextTick先执行,原因是nextTick的队列比Promise队列优先级更高。来看个例子:

const promise = Promise.resolve()setImmediate(() => {  console.log('setImmediate');});promise.then(()=>{    console.log('promise')})process.nextTick(()=>{    console.log('nextTick')})

代码运行结果如下:

settimeout函数用法,js的settimeout方法,队列,任务,定时器

总结

本文从异步基本概念出发一直讲到了浏览器和Node.js的Event Loop,现在我们再来总结一下:

  1. JS所谓的“单线程”只是指主线程只有一个,并不是整个运行环境都是单线程
  2. JS的异步靠底层的多线程实现
  3. 不同的异步API对应不同的实现线程
  4. 异步线程与主线程通讯靠的是Event Loop
  5. 异步线程完成任务后将其放入任务队列
  6. 主线程不断轮询任务队列,拿出任务执行
  7. 任务队列有宏任务队列和微任务队列的区别
  8. 微任务队列的优先级更高,所有微任务处理完后才会处理宏任务
  9. Promise是微任务
  10. Node.js的Event Loop跟浏览器的Event Loop不一样,他是分阶段的
  11. setImmediate和setTimeout(fn, 0)哪个回调先执行,需要看他们本身在哪个阶段注册的,如果在定时器回调或者I/O回调里面,setImmediate肯定先执行。如果在最外层或者setImmediate回调里面,哪个先执行取决于当时机器状况。
  12. process.nextTick不在Event Loop的任何阶段,他是一个特殊API,他会立即执行,然后才会继续执行Event Loop

上面就是本文分享的全部内容,希望可以帮助朋友们,看完了,如果你觉得settimeout函数用法「附:js的settimeout方法」还不错的话记得帮忙点个赞哦,欢迎继续浏览本站,学习更多的知识!

本文发布者:万事通,不代表寂寞网立场,转载请注明出处:https://www.jimowang.com/p/17959.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 jimowangmail@126.com 举报,一经查实,本站将立刻删除。

(0)
上一篇 2022年11月25日 09:03
下一篇 2022年11月25日 09:05

相关推荐

  • 蛟龙号泄密事件:最新海底7000米发现神秘生物/吓疯潜水员

    最近比较忙,今天周伟又抽时间给大家带来了蛟龙号泄密事件,海底7000米发现神秘生物/吓疯潜水员干货,还有关于蛟龙,潜水员,事件的一些干货,认认真真阅读完,若能把我想表达的全部理解,相信你已经离大牛不远了哈! 蛟龙号是中国的载人潜水器,曾创下7000米的记录,而在这潜水的过程中,据说发现过巨型生物,还有吓疯过潜水员。而这些,随着蛟龙号泄密事件的出现,呈现在了我…

    2022年11月19日 自媒体
  • 部落冲突9本最强布阵有哪些「最新部落冲突九本巅峰阵型?」

    小伙伴们大家好,今天卫泓成给大家分析下关于部落冲突9本最强布阵有哪些(部落冲突九本巅峰阵型?)的事情,以及冲突,部落,女巫这些一系列的相关干货内容,既然来了就别走了,好好的静下心把这篇文章阅读完相信你会有一定的收获哦! 《部落冲突》(Clash of Clans,英文简称COC)是由芬兰游戏公司Supercell Oy开发的一款塔防类的策略手游,里面的内容相…

    2022年12月28日
  • 现任上海市现任市长是叫什么名字「最新上海新任市委书记市长」

    美好的1天即将在这里开始,下面就由笔者卫秉岳来一起聊聊现任上海市现任市长是叫什么名字,上海新任市委书记市长,还有关于精神,标题,初心的一些干货,先说明一下,老司机直接飘过吧,主要是讲解给新手朋友们的哈! 今天(6月28日)上午,十二届市委一次全会上新当选的十二届市委常委怀着无比崇敬的心情,集体瞻仰了中共一大会址,重温入党誓词,宣示不忘初心、牢记使命,守护好共…

    2022年12月30日
  • 宣称92%芦荟胶实际只有0.41%

    小伙伴们大家好,今天王向阳将为大家详细介绍一下宣称92%芦荟胶实际只有0.41%的相关信息,还有芦荟,实际,广告,决定书,皮肤的一系列实用干货分享和技巧,如果你想要在这个领域中有所成就,那么你需要先从基础开始学习。 芦荟胶是一种可以舒缓脸部受损的护肤品,有很多人在皮肤受损之后都会选择涂一点芦荟胶进行包养,但近日有消息称宣称92%的芦荟胶实际上只有0.41%,…

    2023年4月1日
  • 父母没重视15岁儿子最终身高153 详细介绍:孩子身高偏矮如何补救

    大家好,今天秦刘权想和大家分享一些关于父母没重视15岁儿子最终身高153,孩子身高偏矮如何补救的见解,还有身高,孩子,父母,儿子,家长的一系列实用干货和技巧分享,这篇文章将会为初学者提供一些实用的方法和技巧,帮助你更好地理解这个领域。 对于孩子的身高,父母都是非常重视的,但最近浙江萧山医院就有一对父母没有及时重视,一名15岁男孩的最终身高只有153厘米。下面…

    2023年4月18日
  • 陈某龙故意散布谣言被依法行拘,具体是什么情况?

    大家好,我是本站的报道员孙婉茹,为您送上最快最全面的新闻资讯,最近有一则陈某龙故意散布谣言被依法行拘,具体是什么情况?引发了大家的广泛关注,成为了网络上的焦点话题,现在,就请跟随我一同探究这个事件的具体情况吧! 陈某龙故意散布谣言被依法行拘,具体是什么情况? 通报全文如下: 2023年4月5日,接上级公安机关指令,我局针对网传涉中国电子科技集团(以下简称中国…

    2023年4月8日