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

相关推荐

  • 非洲致命疾病:出现症状24小时内死亡,排除了是马尔堡病毒或埃博拉病毒的可能

    大家好,我是本站的新闻特派员杨倩,为您带来最权威的新闻报道。近日,非洲致命疾病:出现症状24小时内死亡,排除了是马尔堡病毒或埃博拉病毒的可能的话题引起了不少网友的关注和探讨,成为了网络上的重要话题。下面就让我为大家详细介绍一下这个事件的具体情况吧! 埃博拉、马尔堡,出现在非洲的一些疾病着实可怕,近日,又有新的致命性疾病现身。 据红星新闻报道,在非洲布隆迪,一…

    2023年3月30日
  • 武则天为什么和李世民没孩子「详细讲解:武则天跟了李世民十几年才得到一个」

    美好的1天将要从这里开始啦!今天笔者周羿宇来说说武则天为什么和李世民没孩子,武则天跟了李世民十几年才得到一个,以及关于孩子,皇帝,儿子,关系,后宫这些一系列的精品相关干货,只要你每天都能来,我就能每天整理一些不错的干货分享给你们! 咱们今天不八卦,因为这三人不光关系极其密切,还是中国历史上接续的三位皇帝,其中两位还是同朝皇帝,另一位也是开天辟地独一份的正统皇…

    2023年3月17日 自媒体
  • 周星驰个人资料简介及「推荐周星驰从跑龙套到大导演之路」

    小伙伴们哈喽,这次其他的陈冬雁就不说了,主要就是来讲讲周星驰个人资料简介及,周星驰从跑龙套到大导演之路,还有票房,导演,喜剧片等等等各种相关干货内容,思路决定出路,确实,这个真的很重要,希望能帮到你! 周星驰(Stephen Chow),1962年6月22日出生于 中国香港 ,祖籍 浙江 宁波。华语影视男演员、导演、编剧、制作人、商人[1-2] ,政协委员 …

    2022年12月19日 自媒体
  • 顺丰快递跨省几天能到货 顺丰快递送货时效快

    哈喽,小伙伴们大家好,今天赵紫萱废话就不多说了,直接上干货,标题:顺丰快递跨省几天能到货 顺丰快递送货时效快,以及快递,时间,情况等等各种一系列的相关干货,思路决定出路,确实,这个真的很重要,希望能帮到你! 顺丰快递是目前中国快递行业中速度*快的快递公司之一。顺丰快递是号称365天全年无休,但是公司内部的快递员是实行轮休制的。顺丰快递的上班时间是什么时候呢,…

    2022年12月7日
  • 四川大火「推荐四川凉山大火:最新19名消防员牺牲:」

    今天李禹彤给大家带来了这篇四川大火,四川凉山大火,19名消防员牺牲:干货,还有关于消防员,年轻人,英雄这些的内容,主要就是想给大家提供一个思路分享给大家,毕竟也是经过一系列总结过的哈! 四川大火(四川凉山大火,19名消防员牺牲:) 四川凉山大火,19名消防员牺牲:“我不怕死,只怕保护不了你” 原创2020-03-3122:04·我是Jenny乔 疫情过后,有…

    自媒体 2022年12月5日
  • 2022最新学生坠楼事件「附:成都49中学生坠亡事件调查」

    小伙伴们大家好,今天韩茹讲的文章是2022最新学生坠楼事件,成都49中学生坠亡事件调查,以及其他关于红星,新闻记者,事件的一些相关干货,希望各位能认真阅读。因为,只有这样才能真正理解和掌握! 成都49中的14个监控摄像头,记录了16岁少年小林坠楼前的33分钟。 5月9日18时16分,他从教室后门离开,穿过教学楼、综合楼、实验楼、篮球馆,在负一楼的水泵房停留,…

    2022年12月25日