js的同步与异步
JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。
JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
其实同步和异步,无论如何,做事情的时候都是只有一条流水线(单线程),同步和异步的差别就在于这条流水线上各个流程的执行顺序不同。
最基础的异步是setTimeout和setInterval函数,很常见,但是很少人有人知道其实这就是异步,因为它们可以控制js的执行顺序。我们也可以简单地理解为:可以改变程序正常执行顺序的操作就可以看成是异步操作。</pre>
<script type="text/javascript">
console.log( "1" );
setTimeout(function() {
console.log( "2" )
}, 0 );
setTimeout(function() {
console.log( "3" )
}, 0 );
欢迎加入全栈开发交流划水交流圈:582735936
面向划水1-3年前端人员
帮助突破划水瓶颈,提升思维能力
setTimeout(function() {
console.log( "4" )
}, 0 );
console.log( "5" );
</script> </pre>
复制代码
尽管我们设置了setTimeout(function,time)中的等待时间为0,结果其中的function还是后执行。
火狐浏览器的api文档有这样一句话:Because even though setTimeout was called with a delay of zero, it's placed on a queue and scheduled to run at the next opportunity, not immediately. Currently executing code must complete before functions on the queue are executed, the resulting execution order may not be as expected.
意思就是:尽管setTimeout的time延迟时间为0,其中的function也会被放入一个队列中,等待下一个机会执行,当前的代码(指不需要加入队列中的程序)必须在该队列的程序完成之前完成,因此结果可能不与预期结果相同。
这里说到了一个“队列”(即任务队列),该队列放的是什么呢,放的就是setTimeout中的function,这些function依次加入该队列,即该队列中所有function中的程序将会在该队列以外的所有代码执行完毕之后再以此执行,这是为什么呢?因为在执行程序的时候,浏览器会默认setTimeout以及ajax请求这一类的方法都是耗时程序(尽管可能不耗时),将其加入一个队列中,该队列是一个存储耗时程序的队列,在所有不耗时程序执行过后,再来依次执行该队列中的程序。
又回到了最初的起点——javascript是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。于是就有一个概念——任务队列。如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。于是JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。
于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。
具体来说,异步运行机制如下:
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
"任务队列"是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈"了。主线程读取"任务队列",就是读取里面有哪些事件。
"任务队列"中的事件,除了IO设备的事件以外,还包括一些用户产生的事件(比如鼠标点击、页面滚动等等),比如$(selectot).click(function),这些都是相对耗时的操作。只要指定过这些事件的回调函数,这些事件发生时就会进入"任务队列",等待主线程读取。
所谓"回调函数"(callback),就是那些会被主线程挂起来的代码,前面说的点击事件$(selectot).click(function)中的function就是一个回调函数。异步任务必须指定回调函数,当主线程开始执行异步任务,就是执行对应的回调函数。例如ajax的success,complete,error也都指定了各自的回调函数,这些函数就会加入“任务队列”中,等待执行。
本次给大家推荐一个免费的学习群,里面概括移动应用网站开发,css,html,webpack,vue node angular以及面试资源等。
js的同步与异步的更多相关文章
- JS中同步和异步
首先,我们要知道,JavaScript的本质是一门浏览器脚本语言,在执行的时候是一行一行的执行,只有前面的代码执行完了才会执行后面的代码.JS是单线程语言指的就是这个意思. 同步和异步其实在进行任务执 ...
- js中同步与异步处理方法
在使用异步请求时,有时需要将异步请求的结果返回给另一个js函数,此种情况下会出现未等异步请求返回请求结果,该发送请求所在js函数已经执行完后续操作,即已经执行return ,这样会导致return的结 ...
- JS的同步和异步加载
引言 JS的“加载”不能理解为下载,它是分为两个部分:下载,执行.默认的JS加载是同步的,因为浏览器需要一个稳定的DOM结构,而执行JS时可能会对DOM造成改变,所以在执行JS时一定会阻塞HTML的渲 ...
- js中同步与异步请求方式
异步请求方式: $.ajax({ url : 'your url', data:{name:value}, cache : false, async : true, type : "POST ...
- js脚本同步、异步与延迟
一般,我们通过src引入js文件时建议在页面末尾引入,因为会阻塞页面的渲染.defer和async可以达到同样效果 当HTML解析器遇到<script>元素时,它必须先执行脚本,然后再恢复 ...
- JS中同步与异步
不讲过多定义,举两个例子说明下 例一: console.log(100); setTimeout(function(){ console.log(200); },1000); console.log( ...
- JS同步与异步;
JS的同步与异步 同步:代买从上往下的执行 异步:每个模块各执行各的,同时执行,互不干扰 四个异步事件:(1)定时器(2)ajax(3)时间的绑定(4)回调函数 现在用定时器来说一说setTimeOu ...
- JS三座大山再学习 ---- 异步和单线程
本文已发布在西瓜君的个人博客,原文传送门 前言 写这一篇的时候,西瓜君查阅了很多资料和文章,但是相当多的文章写的都很简单,甚至互相之间有矛盾,这让我很困扰:同时也让我坚定了要写出一篇好的关于JS异步. ...
- 【Mocha.js 101】同步、异步与 Promise
前情提要 在上一篇文章<[Mocha.js 101]Mocha 入门指南>中,我们提到了如何用 Mocha.js 进行前端自动化测试,并做了几个简单的例子来体验 Mocha.js 给我们带 ...
随机推荐
- PTA数据结构与算法题目集(中文) 7-16
PTA数据结构与算法题目集(中文) 7-16 7-16 一元多项式求导 (20 分) 设计函数求一元多项式的导数. 输入格式: 以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过1000 ...
- 大曾Blogs使用说明书😊——Super ITZ
大曾Blogs使用说明书 先敲黑板,四句话: pipe搜索,简洁,用于跳转,博客园及csdn和github 博客园炫酷界面,用于查看主要博文 csdn所有博客汇总,查看详细信息 github项目源码汇 ...
- 【Linux】LAMP环境搭建(简易版)
一. 辅助软件包安装 准备工作:1.Linux系统准备 恢复快照(初始化安装) 设置IP 关闭SELINUX 配置yum源 2.yum -y install gcc gcc-c++ 3.关闭防火墙 4 ...
- Redis对象——集合(Set)
集合类型 (Set) 是一个无序并唯一的键值集合.它的存储顺序不会按照插入的先后顺序进行存储. 集合类型和列表类型的区别如下: 列表可以存储重复元素,集合只能存储非重复元素: 列表是按照元素的先后顺序 ...
- Android AndroidManifest.xml详解
AndroidManifest.xml简述: AndroidManifest.xml 是每个android程序中必须的文件.它位于整个项目的根目录,描述了package中暴露的组件(activitie ...
- go中的面向对象总结
我们总结一下前面看到的:Go 没有类,而是松耦合的类型.方法对接口的实现. OO 语言最重要的三个方面分别是:封装,继承和多态,在 Go 中它们是怎样表现的呢? 封装(数据隐藏):和别的 OO 语言有 ...
- linux系统管理,查看系统资源
free 查看内存使用情况 -b ===> 以byte为单位 -k ===> 以Kb为单位 -m ===> 以Mb为单位 -g ===> 以Gb为单位 -t ...
- I/O流之--转换流:InputStreamReader 和InputStreamWriter
I/O流之--转换流:InputStreamReader 和InputStreamWriter 分类: java2014-07-01 15:30 815人阅读 评论(0) 收藏 举报 目录(?)[ ...
- 如何利用 githob 上传自己的网站
如何搭建自己的网页是每个学前端伙伴不可缺少的一个过程,特意去看过很多如何搭建的教程,但都看不懂觉得很麻烦, 在慢慢的学习中接触到githob,发现了一个大宝藏(如果一个code都不认识githob 那 ...
- iOS线程数量监控工具
简单却强大的线程监控工具 KKThreadMonitor :当线程过多或瞬间创建大量子线程(线程爆炸),控制台就打印出所有的线程堆栈.便于分析造成子线程过多或线程爆炸的原因. /******* 线程爆 ...