javascript 等待指定时间_javascript的单线程和任务队列

一、JavaScript为什么设计为单线程?

JavaScript语言的一大特点就是单线程,换言之就是同一个时间只能做一件事。其他任务都必须在后面排队等待。

for(var i = 0; i < 5; i++) {console.log(i);
}
console.log('end');

上面的代码,只有for循环执行完毕,才会执行end;

JavaScript 之所以采用单线程,而不是多线程,跟历史有关系。JavaScript 从诞生起就是单线程,原因是不想让浏览器变得太复杂,因为多线程需要共享资源、且有可能修改彼此的运行结果,对于一种网页脚本语言来说,这就太复杂了。如果 JavaScript 同时有两个线程,一个线程在网页 DOM 节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?是不是还要有锁机制?所以,为了避免复杂性,JavaScript 一开始就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段 JavaScript 代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。JavaScript 语言本身并不慢,慢的是读写外部数据,比如等待 Ajax 请求返回结果。这个时候,如果对方服务器迟迟没有响应,或者网络不通畅,就会导致脚本的长时间停滞。

如果排队是因为计算量大,CPU 忙不过来,倒也算了,但是很多时候 CPU 是闲着的,因为 IO 操作(输入输出)很慢(比如 Ajax 操作从网络读取数据),不得不等着结果出来,再往下执行。JavaScript 语言的设计者意识到,这时 CPU 完全可以不管 IO 操作,挂起处于等待中的任务,先运行排在后面的任务。等到 IO 操作返回了结果,再回过头,把挂起的任务继续执行下去。这种机制就是 JavaScript 内部采用的“事件循环”机制(Event Loop)。
单线程模型虽然对 JavaScript 构成了很大的限制,但也因此使它具备了其他语言不具备的优势。如果用得好,JavaScript 程序是不会出现堵塞的,这就是为什么 Node 可以用很少的资源,应付大流量访问的原因。

为了利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程,但是子线程完全受主线程控制,且不得操作 DOM。所以,这个新标准并没有改变 JavaScript 单线程的本质。二、同步任务和异步任务
程序里面所有的任务,可以分成两类:同步任务(synchronous)和异步任务(asynchronous)。
同步任务是那些没有被引擎挂起、在主线程上排队执行的任务。只有前一个任务执行完毕,才能执行后一个任务。
异步任务是那些被引擎放在一边,不进入主线程、而进入任务队列的任务。只有引擎认为某个异步任务可以执行了(比如 Ajax 操作从服务器得到了结果),该任务(采用回调函数的形式)才会进入主线程执行。排在异步任务后面的代码,不用等待异步任务结束会马上运行,也就是说,异步任务不具有“堵塞”效应。
举例来说,Ajax 操作可以当作同步任务处理,也可以当作异步任务处理,由开发者决定。如果是同步任务,主线程就等着 Ajax 操作返回结果,再往下执行;如果是异步任务,主线程在发出 Ajax 请求以后,就直接往下执行,等到 Ajax 操作有了结果,主线程再执行对应的回调函数。

三、任务队列和事件循环
JavaScript 运行时,除了一个正在运行的主线程,引擎还提供一个任务队列(task queue),里面是各种需要当前程序处理的异步任务。(实际上,根据异步任务的类型,存在多个任务队列。为了方便理解,这里假设只存在一个队列。)
首先,主线程会去执行所有的同步任务。等到同步任务全部执行完,就会去看任务队列里面的异步任务。如果满足条件,那么异步任务就重新进入主线程开始执行,这时它就变成同步任务了。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。
异步任务的写法通常是回调函数。一旦异步任务重新进入主线程,就会执行对应的回调函数。如果一个异步任务没有回调函数,就不会进入任务队列,也就是说,不会重新进入主线程,因为没有用回调函数指定下一步的操作。
JavaScript 引擎怎么知道异步任务有没有结果,能不能进入主线程呢?答案就是引擎在不停地检查,一遍又一遍,只要同步任务执行完了,引擎就会去检查那些挂起来的异步任务,是不是可以进入主线程了。这种循环检查的机制,就叫做事件循环(Event Loop)。维基百科的定义是:“事件循环是一个程序结构,用于等待和发送消息和事件(a programming construct that waits for and dispatches events or messages in a program)”。

范例1

 let timer1 = setTimeout(() => {console.log(1)}, 0)console.log(2)

以上代码先输出1,立即输出2 延时0ms和延时1ms效果其实是一样的,定时器有最小时间粒度。[1]定时器最小时间间隔:在苹果机上的最小时间间隔是10ms,在Windows系统上的最小时间间隔大约是15ms。Firefox中定义的最小时间间隔是10ms,而HTML5规范中定义的最小时间间隔是4ms

范例2

let t = ture
let timer = setTimeout(() {t = false
}, 1000)
while (t) {}
console.log('end');

以上代码是一个死循环,结果是浏览器卡死,永远不会输出'end'

范例3

const useTime = t => {let start = Date.now()while (Date.now() - start < t) {}
}
let timer1 = setTimeout(() => {console.log(3)
}, 500)
let timer2 = setTimeout(() => {console.log(4)
}, 1000)
console.log(1)
useTime(2000)
console.log(2)

以上代码立即输出1,等待2秒后同时依次输出2、3、4,因为setTimeout是异步任务,而timer1比time2先注册,且timer1比timer2定时时间短。又因为useTime函数执行时间是2s,所以执行完之后,将立即执行任务队列里的timer1、timer2,所以等待2秒后将依次输出2、3、4。
执行流程
1、进入全局执行上下文
创建由第三方计时模块管理的timer1,timer1会在500ms后把任务fn1放入任务队列
创建由第三方计时模块管理的timer2,time2会在1000ms后把任务fn2放入任务队列
输出1
2、进入useTime执行上下文
执行代码耗时2000ms,退出useTime执行上下文
在500ms和1000ms时timer1和timer2各自完成投放,此操作不属于JS主线程
3、返回全局执行上下文
输出2
同步任务执行完毕 开始扫描任务队列
取出队列的fn1
4、进入fn1执行上下文
输出3,退出fn1执行上下文
取出队列的fn2
5、进入fn2执行上下文
输出4,退出fn2执行上下文
循环扫描任务队列
线程、事件循环和任务队列
Javascript是单线程的,但是却能执行异步任务,这主要是因为 JS 中存在事件循环(Event Loop)和任务队列(Task Queue)事件循环:JS 会创建一个类似于 while (true) 的循环,每执行一次循环体的过程称之为Tick。每次Tick的过程就是查看是否有待处理事件,如果有则取出相关事件及回调函数放入执行栈中由主线程执行。待处理的事件会存储在一个任务队列中,也就是每次Tick会查看任务队列中是否有需要执行的任务。任务队列:异步操作会将相关回调添加到任务队列中。而不同的异步操作添加到任务队列的时机也不同,如onclick, setTimeout,ajax 处理的方式都不同,这些异步操作是由浏览器内核的webcore来执行的,webcore包含下图中的3种 webAPI,分别是DOM Bindingnetworktimer模块。

  • DOM Binding 模块处理一些DOM绑定事件,如onclick事件触发时,回调函数会立即被webcore添加到任务队列中。
  • network 模块处理Ajax请求,在网络请求返回时,才会将对应的回调函数添加到任务队列中。
  • timer 模块会对setTimeout等计时器进行延时处理,当时间到达的时候,才会将回调函数添加到任务队列中。

主线程:JS 只有一个线程,称之为主线程。而事件循环是主线程中执行栈里的代码执行完毕之后,才开始执行的。所以,主线程中要执行的代码时间过长,会阻塞事件循环的执行,也就会阻塞异步操作的执行。只有当主线程中执行栈为空的时候(即同步代码执行完后),才会进行事件循环来观察要执行的事件回调,当事件循环检测到任务队列中有事件就取出相关回调放入执行栈中由主线程执行。
参考:

小爽4230:单线程、任务队列、同步与异步​zhuanlan.zhihu.com

饥人谷课件:

https://static.xiedaimala.com/xdml/file/f40ceb64-df08-4420-9226-7f76dbff15d5/2019-12-20-11-14-11.pdf​static.xiedaimala.comjavascript中单线程和任务队列​www.jianshu.com
454b244a885045cdc9ed5838106236cf.png

参考

  1. ^定时器最小时间间隔:在苹果机上的最小时间间隔是10ms,在Windows系统上的最小时间间隔大约是15ms。Firefox中定义的最小时间间隔是10ms,而HTML5规范中定义的最小时间间隔是4ms。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/489313.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2019年云计算行业深度报告

来源&#xff1a;西部证券 导语 根据 Gartner 数据 2018 年全球公有云市场规模达到 1392 亿美元&#xff0c;2015 年至 2018 年复合增长 28.24%&#xff0c;预计 2021 年规模将达到 2461 亿美元。 一、云计算蓬勃发展&#xff0c;驱动数据中心基础设施采购 1.1 云计算蓬勃发展&…

dataframe 一列的不同值_pandas | 详解DataFrame中的apply与applymap方法

点击上方蓝字&#xff0c;关注并星标&#xff0c;和我一起学技术。今天是pandas数据处理专题的第5篇文章&#xff0c;我们来聊聊pandas的一些高级运算。在上一篇文章当中&#xff0c;我们介绍了panads的一些计算方法&#xff0c;比如两个dataframe的四则运算&#xff0c;以及da…

https访问http加载不出图片_前端解决第三方图片防盗链的办法

作者&#xff1a;biaochenxuying转发链接&#xff1a;https://github.com/biaochenxuying/blog/issues/31问题笔者网站的图片都是上传到第三方网站上的&#xff0c;比如 简书、掘金、七牛云上的&#xff0c;但是最近简书和掘金都开启了 防盗链&#xff0c;防止其他网站访问他们…

java spring boot 注解验证_如何理解Java原生注解和Spring 各种注解?

作者&#xff1a;digdeep.cnblogs.com/digdeep/p/4525567.html导引Spring中的注解大概可以分为两大类&#xff1a;spring的bean容器相关的注解&#xff0c;或者说bean工厂相关的注解&#xff1b;springmvc相关的注解。spring的bean容器相关的注解有&#xff1a;Required&#x…

数据驱动的未来城市八大趋势

来源&#xff1a;微信公众号腾讯研究院 趋势一 更可持续 城市的发展要为整个人类文明的永续传承和为后人能享受到更高质量的生活为目标。一个更加智慧的城市&#xff0c;势必具有着更加可持续发展的能力。新科技为城市的核心系统的设施提供了更为智能、高效率的调配方案&#x…

浪潮服务器bios怎么找回密码,服务器BIOS密码丢失解决方法

先升级iBMC&#xff0c;再升级bios&#xff0c;可以将bios密码重置。此案例以RH2288为例&#xff1a;1、登录到iBMC web界面&#xff0c;点击系统设置里的固件升级&#xff0c;将BMC升级包image.hpm上传后&#xff0c;点击升级&#xff0c;因为BMC主备两个镜像&#xff0c;需要…

看了中国与别国的科研差距后,究竟什么才是真正的科研精神?

来源&#xff1a;募格学术 目前&#xff0c;中国的科研环境越来越好&#xff0c;单就硬件上来讲&#xff0c;与欧美发达国家没有很大差别。2014年&#xff0c;中国研发投入13400亿元&#xff0c;占GPD2.1%&#xff0c;这个比例超过了欧盟。然而&#xff0c;引人深思的是中国缺席…

numpy 转置_Numpy基础:数组转置和轴对换

转置&#xff08;transpose&#xff09;是重塑的一种特殊形式&#xff0c;它返回的是源数据的视图&#xff08;不会进行任何复制操作&#xff09;。数组不仅有transpose方法&#xff0c;还有一个特殊的T属性。In[70]:arrnp.arange(15).reshape((3,5))In[71]:arrOut[71]: array(…

word2016 图片去底灰_看来看去,还是高级灰最耐看,喜欢现代简约风的你,选它准不会错...

经常看到有人问&#xff1a;不想要大白墙&#xff0c;给家里装点什么颜色好&#xff1f;这个问题其实没有固定答案&#xff0c;毕竟对于色彩的感受&#xff0c;每个人都不一样。没有固定答案不代表没有选择&#xff0c;好看又百搭的色彩有很多&#xff0c;但是能做到经典与时尚…

惊人的预测——来自2019麦肯锡报告《中国与世界》完整版

来源&#xff1a;麦肯锡全球研究院 自从中国开始建立与世界各国的经济往来、拥抱市场机制&#xff0c;并积极接纳全球最佳实践以后&#xff0c; 中国经济便迈入了腾飞阶段。如今&#xff0c;中国已凭借其庞大的经济体量跻身全球大国之列。中国在2013年跃居全球第一大商品贸易国…

匹夫细说C#:庖丁解牛迭代器,那些藏在幕后的秘密

匹夫细说C#&#xff1a;庖丁解牛迭代器&#xff0c;那些藏在幕后的秘密c#语言规范阅读目录0x00 前言0x01 你好&#xff0c;迭代器0x02 原来是状态机呀0x03 状态管理0x04 总结回到目录0x00 前言在匹夫的上一篇文章《匹夫细说C#&#xff1a;不是“栈类型”的值类型&#xff0c;从…

法国公布“人机协同”项目第二批研究计划

来源&#xff1a;法国《航宇防务》/图片来自互联网出处&#xff1a;国防科技要闻近日&#xff0c;法国公布了“人机协同”&#xff08;MMT&#xff09;项目第二批研究计划。MMT项目由法国武器装备总署&#xff08;DGA&#xff09;管理&#xff0c;于2018年3月启动&#xff0c;是…

xp打印服务器win10的系统连接不上,Win10系统访问WinXP系统共享打印机却连接不了的解决方法...

在今天的Win10系统的使用教程中&#xff0c;我们将来学习的是Win10系统访问WinXP系统共享打印机却连接不了的问题。不过&#xff0c;小编得事先说一下&#xff0c;Win10系统是可以直接连接WinXP系统共享打印机的&#xff0c;只是个别用户由于一些原因而出现这个状况&#xff0c…

c++ map初始化同时赋值_Golang入门教程——map篇

点击上方蓝字&#xff0c;和我一起学技术。今天是golang专题的第7篇文章&#xff0c;我们来聊聊golang当中map的用法。map这个数据结构我们经常使用&#xff0c;存储的是key-value的键值对。在C/java当中叫做map&#xff0c;在Python中叫做dict。这些数据结构的名称虽然不尽相同…

知识图谱简史:从1950到2019

来源&#xff1a;专知 地址&#xff1a;http://knowledgegraph.today/paper.html 作者 | Claudio Gutierrez 、 Juan F. Sequeda 编译 | Xiaowen 目录&#xff1a; 知识图谱可以被认为是实现计算机科学的早期愿景&#xff0c;即创建能够大规模集成知识和数据的智能系统。“知识…

影响计算机算法世界的十位大师(上)

来源&#xff1a;数学职业家1、伟大的智者——Don E.Knuth&#xff0c;中文名&#xff1a;高德纳(1938-)算法和程序设计技术的先驱者。Oh,God!一些国外网站这样评价他。一般说来&#xff0c;不知道此人的程序员是不可原谅的。其经典著作《计算机程序设计艺术》更是被誉为算法中…

echars显示折点数据_数据可视化的基础语法

数据可视化的基础语法可视化主要是以图像来展示数据间的关系&#xff0c;常见的图形种类有折线图,散点图,条形图&#xff0c;直方图&#xff0c;饼图。此外在接下来课程中还会用到箱线图&#xff0c;热力图&#xff0c;蜘蛛图&#xff0c;表示二元变量分布和成对关系的视图。今…

cad快捷键文件路径_办公格式转太难不会看这里!CAD、PDF、Word、Excel、TXT教你玩转...

办公格式转&#xff0c;你遇到最难解决的问题是哪些&#xff1f;办公格式转&#xff0c;最让你头疼的文件格式是哪些&#xff1f;办公格式转&#xff0c;你最想要学习转换格式有哪些&#xff1f;我&#xff1a;Word、Excel、PPT、TXT、CAD、PDF、JPG统统都想要进行解决&#xf…

80x86汇编—分支循环程序设计

文章目录 查表法: 实现16进制数转ASCII码显示计算AX的绝对值判断有无实根地址表形成多分支从100,99,...,2,1倒序累加输入一个字符&#xff0c;然后输出它的二进制数大小写转换大写转小写小写转大写 冒泡排序剔除空格 查表法: 实现16进制数转ASCII码显示 题目要求&#xff1a; …

织梦服务器系统win10,WIN服务器爆破DEDECMS后台目录

利用脚本python&#xff1a;#!/usr/bin/env python/** author Mochazz* team 红日安全团队* env pyton3**/import requestsimport itertoolscharacters "abcdefghijklmnopqrstuvwxyz0123456789_!#"back_dir ""flag 0url "http://192.168.1.9/t…