你应该知道,javascript语言是一门“单线程”的语言,不像java语言,类继承Thread再来个thread.start就可以开辟一个线程,所以,javascript就像一条流水线,仅仅是一条流水线而已,要么加工,要么包装,不能同时进行多个任务和流程。

那么这里说的同步和异步到底是什么呢?如果你真的不懂,我希望你认真读完这篇文章。其实我个人觉得js官方的文档在使用两个词的时候并不准确,包括很多其他词汇,都只是听起来高深,但实际应用好像跟这些词没半毛钱关系。例如“事件委托”这个词,不知道的人乍一看谁又能说出“事件委托”是什么意思?委托什么事件?怎么个委托,我看不如干脆就叫“事件在外层元素中的捕获”,虽然长一点,一下就能看懂。

回归正轨,“同步”——一下就让人想到“一起”这个词;“异步”呢,从字面来讲,好像是在不同的(异)的ways上do something,那首先想到的词可能是“一边...一边...”,比如‘小明一边吃雪糕一边写作业’,这完全没毛病,雪糕吃完了,作业也写完了,这就是异步?那就大错特错了!

其实同步和异步,无论如何,做事情的时候都是只有一条流水线(单线程),同步和异步的差别就在于这条流水线上各个流程的执行顺序不同。

最基础的异步是setTimeout和setInterval函数,很常见,但是很少人有人知道其实这就是异步,因为它们可以控制js的执行顺序。我们也可以简单地理解为:可以改变程序正常执行顺序的操作就可以看成是异步操作。如下代码:

[javascript] view plain copy
  1. <script type="text/javascript">
  2. console.log( "1" );
  3. setTimeout(function() {
  4. console.log( "2" )
  5. }, 0 );
  6. setTimeout(function() {
  7. console.log( "3" )
  8. }, 0 );
  9. setTimeout(function() {
  10. console.log( "4" )
  11. }, 0 );
  12. console.log( "5" );
  13. </script>

输出顺序是什么呢?

可见,尽管我们设置了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也都指定了各自的回调函数,这些函数就会加入“任务队列”中,等待执行。

转载于:https://www.cnblogs.com/yangguoe/p/8433872.html

JS中同步与异步的理解相关推荐

  1. JS中同步和异步的区别

    JS中同步和异步的区别 js是一门单线程语言,所谓"单线程",就是指一次只能完成一件任务.如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推.如果一个任务耗 ...

  2. 一篇文章理解JS中同步任务和异步任务以及宏任务与微任务的原理和执行机制

    前言: javascript是一种单线程编程语言, 一般来说它的执行顺序是按照从上到下执行,但是有些特殊情况则会改变这样的执行顺序,我们需要理解和掌握其中的原理,需要了解同步任务和异步任务以及宏任务和 ...

  3. Java中同步和异步的区别是什么?优点缺点以及概念理解

    同步:提交请求--->等待服务器处理--->服务器处理完毕返回的这个期间客户端浏览器不能干别的事 异步:请求通过事件触发--->服务器处理(这时客户端浏览器还可以做其他的事情)--- ...

  4. Node中同步与异步的方式读取文件

    场景 Node.js最大的特点就是异步式I/O(或者非阻塞I/O)与事件紧密结合的编程模式.这种模式与传统的同步式I/O线性的编程思路有很大的不同,因为控制流很大程度上要靠事件和回调函数来组织,一个逻 ...

  5. JS中同步和异步问题及其区别

    1.同步和异步 首先,我们浏览器常用的是JS语言,但其实相比于JAVA来说,JS其实是单线程语言,JavaScript在同一个时间只能做一件事,单线程意味着,如果在同个时间有多个任务的话,这些任务就需 ...

  6. js中的prototype的理解

    2019独角兽企业重金招聘Python工程师标准>>> JS中的prototype是JS中比较难理解的一个部分 1 原型法设计模式 在.Net中可以使用clone()来实现原型法 原 ...

  7. Js中函数式编程的理解

    函数式编程的理解 函数式编程是一种编程范式,可以理解为是利用函数把运算过程封装起来,通过组合各种函数来计算结果.函数式编程与命令式编程最大的不同其实在于,函数式编程关心数据的映射,命令式编程关心解决问 ...

  8. JS中对于prototype的理解

    JS中的prototype是JS中比较难理解的一个部分 本文基于下面几个知识点: 1 原型法设计模式 在.Net中可以使用clone()来实现原型法 原型法的主要思想是,现在有1个类A,我想要创建一个 ...

  9. Js中匿名函数的理解

    目录 1.js中匿名函数的N种写法 最常见的用法: 2.JavaScript 匿名函数及闭包 2.1 匿名函数 2.1.1 函数的定义 2.1.2 匿名函数的创建 2.2 闭包 2.3 举例 2.4 ...

最新文章

  1. 如何使用Nsight Compute?
  2. C++——简单数据类型及布尔类型
  3. 用 .NET Memory Profiler 跟踪.net 应用内存使用情况--基本应用篇
  4. ARM常用的调试方式与ARM培训班常见的调试方法
  5. java后台异步任务执行器TaskManager
  6. 乌班图安装pycharm
  7. 阐述HTML语言的基本语法规则,HTML基本语法和语义写法规则与实例
  8. 抽屉式(菜单)导航实例模板,设计师喜欢哪款?
  9. 每日算法系列【LeetCode 470】用 Rand7() 实现 Rand10()
  10. 【转】纯干货:PS高手完全自学宝典(原创文章)
  11. iOS 播放视频的基本步骤
  12. 隐形眼镜的评价分析报告
  13. h61 nvme硬盘_谁更快?PCIe 4.0时代的NVMe固态硬盘性能对决
  14. 51单片机实现万年历
  15. 【编程实践】为了带你搞懂RPC,我们手写了一个RPC框架
  16. 我不爱的那个女人[转]
  17. 紫光同创国产FPGA学习之IP Compiler
  18. 巧用计算机课件,如何用电脑录制ppt讲解视频?
  19. python不改变图片尺寸压缩到指定大小
  20. vue移动端富文本编辑器vue-html5-editor

热门文章

  1. 组成关系映射(注解)
  2. iOS中的UIAlertView之新方法(弹出警告框)
  3. 如何使用ember下拉框组件??
  4. MAC OS X 10.8 操作远程SSH服务器 + 无密码输入使用SSH服务器
  5. ​rsync应用拓展多模块同步13
  6. AWS Storage Gateway 分类
  7. 无线渗透--wifiphisher之wifi钓鱼获取wifi密码
  8. windows下scrapy安装问题,以及Twisted安装报错(error: Microsoft Visual C++ 14.0 is required.)完美解决办法...
  9. 查找运行时间超过1天的frmweb进程
  10. XSS挑战之旅闯关笔记