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

相关推荐

  • 和天下香烟多少钱一包 和成天下香烟价格排行榜 香烟价格网

    美好的1天将要从这里开始啦!今天笔者杨羽彤来说说和天下香烟多少钱一包 和成天下香烟价格排行榜 香烟价格网,还有香烟,多少钱,天下等等等各种相关干货内容,成功的路上不会一帆风顺,每一个成功的背后都有一个惊人的故事。 和天下香烟是湖南中烟旗下白沙品牌推出的产品,在高档香烟中销量一直保持第一,坐上了国内高档香烟的头把交椅,那么和天下香烟多少钱一包呢?下面就让杨羽彤…

    2022年10月16日 自媒体
  • 清醒的反义词是什么「推荐最佳答案」「推荐清醒的反义词熟练的反义词」

    首先,赵静感谢你能坚持经常过来关注我!下面我就来说说清醒的反义词是什么,最佳答案,清醒的反义词熟练的反义词,以及反义词,词语,最佳答案,意义,形意等等相关的各种干货,如果你是老司机,你可能觉得很简单,但如果你是新手,你可能就不这么想了。 知识背景 中国汉语言博大精深,只有正确理解,仔细辨别,才能准确掌握音形意,把握其内涵,增强表达效果。 为了便于掌握和运用,…

    2023年3月12日
  • 淘宝小二在哪里?如何找到淘宝小二

    今天孙虎给大家带来了这篇淘宝小二在哪里?如何找到淘宝小二干货,以及工作台,页面,选项这些一系列的相关干货内容,其实这个内容对于新手来说还是挺重要的,因为涉及面很大。如果你认真读了,一定会有所收获! 只要你接触淘宝的时间够长,无论你是淘宝卖家还是淘宝买家,都应该知道淘宝小二。淘宝小二其实就是淘宝的客服,负责处理买家卖家之间的矛盾纠纷等问题,如果你在淘宝上发生了…

    2022年12月16日
  • 2023年三胎国家奖励多少钱_2023年三胎政策最新消息

    大家好,今天赵祝河为大家带来了一些关于2023年三胎国家奖励多少钱,2023年三胎政策最新消息的专业知识,还有关于政策,最新消息,多少钱,国家,家庭这些的最新实用干货和分享内容,在整理自己的思路之后,我写下了这篇文章,希望能够为大家提供一些有用的建议和指导,让你们更好地把握思路。 我们都知道,现在国家为了鼓励生育,防止人口老龄化实行了三胎政策,那么今年已经是…

    2023年5月2日
  • office激活工具kms下载「kms激活工具下载」

    大家好,今天褚福星给大家讲解下关于office激活工具kms下载,kms激活工具下载的事情,还有批量,通道,版本等等等各种相关干货内容,这篇文章对新手朋友来说是比较重要的,因为涉及到各个方面,阅读完你一定能有所收获! 在职场办公中,我们会经常性地使用office办公软件,很多小伙伴应该有这样的体验,自己百度去下载office安装包,会出现各种捆绑软件或者是有…

    2022年12月3日 自媒体
  • 白酒排行榜前十名「中国十大名酒排名」

    很高兴你能坚持经常过来支持笔者:朱泽涵,今天就来说说关于白酒排行榜前十名,中国十大名酒排名,以及名酒,白酒,排行榜的相关内容干货,认真阅读完,把我想表达的思路完全理解,相信你很快就可以掌握! 白酒排行榜前十名(中国十大名酒排名) 1、茅台(中国十大名酒之首,白酒当之无愧的头牌) 2、五粮液(浓香型白酒中的王者,四次被评选为中国名酒) 3、泸州老窖(泸州老窖特…

    2022年10月10日 自媒体