(本片文章如果你能耐着性子看我,保证会对同步和异步有一个非常深刻的理解)

JavaScript是单线程执行,所谓的单线程呢就是指如果有多个任务就必须去排队,前面任务执行完成后,后面任务再执行。因为JavaScript是一门单线程语言,所以我们可以得出结论: 
JavaScript是按照语句出现的顺序执行的

一、同步和异步

同步

如果在函数返回结果的时候,调用者能够拿到预期的结果(就是函数计算的结果),那么这个函数就是同步的.

console.log('hello');//执行后,获得了返回结果

如果函数是同步的,即使调用函数执行任务比较耗时,也会一致等待直到得到执行结果。(所以在JavaScript中对于耗时的操作或者时间不确定的操作,使用异步就成了必然的选择。)如下面的代码:

function wait(){
for(var i=0;i<9999999999;i++){
if (i==9999999999){
console.log('i需要慢慢的加1直到99999999999999');
return
}
}
}
wait();
console.log('要等到i增加到9999999999(也就是wait()函数执行完毕)才能打印出这句话,大概要等10秒左右');

上面代码中,函数wait是一个耗时程序,持续10秒左右,在它执行的这漫长的10秒中,下面的console.log()函数只能等待,这就是同步。所以在JavaScript中对于耗时的操作或者时间不确定的操作,使用异步就成了必然的选择。

异步

如果在函数返回的时候,调用者还不能够得到预期结果,而是将来通过一定的手段得到(例如回调函数),这就是异步。例如处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程等等。 如果函数是异步的,发出调用之后,马上返回,但是不会马上返回预期结果。调用者不必主动等待,当被调用者得到结果之后会通过回调函数主动通知调用者。

function wait(){//下面每句打印的话前面的数字是她们在控制台打印出来之后的先后顺序
console.log('1:wait()函数开始执行了');
var time1 = (new Date()).getTime();//获取当前的unix时间戳
setTimeout(function () {
var time2=new Date().getTime();
while((time2-time1 > 5000)){
console.log('4:5秒过去了');
return
}
},5000)//等5秒然后获取当前的unix时间戳
console.log('2:wait()函数执行结束了');
}
wait();
console.log('3:虽然js会先执行上面的wait函数,并且里面有个5秒的定时器,但是定时器函数是异步的,意思就是说wait()函数里面的定时器启动,并开始计时的时候并不影响继续执行定时器之后的代码');

上面的代码的打印结果:

例二:

//打印出什么   3 3  3
for(var i=0;i<3;i++){
setTimeout(function(){//凡是异步操作,一定是在所有同步操作执行完毕之后才能执行,也就是for循环执行完毕之后才能执行定时器里面的代码,此时i=3了
console.log(i);
},100)
}

二、单线程与多线程

了解完同步和异步之后,我们再来看看我们的问题:单线程又怎么会有异步呢? 
JavaScript其实就是一门语言,说是单线程还是多线程得结合具体运行环境。众所周知,js的运行环境就是浏览器,具体由js引擎取解析和执行。下面我们来了解下浏览器。

浏览器

一个浏览器通常由以下几个常驻的线程:

  • 渲染引擎线程,负责页面的渲染
  • js引擎线程,负责js的解析和执行
  • 定时触发器线程,处理setInterval和setTimeout
  • 事件触发线程,处理DOM事件
  • 异步http请求线程,处理http请求

要注意的是渲染引擎和js引擎线程是不能同时进行的。渲染线程在执行任务的时候,js引擎线程会被挂起。因为若是在渲染页面的时候,js处理了DOM,浏览器就不知道该听谁的了

JS引擎

通常讲到浏览器的时候,我们会说到两个引擎:渲染引擎和JS引擎。
1、渲染引擎:Chrome/Safari/Opera用的是Webkit引擎,IE用的是Trdent引擎,FireFox用的是Gecko引擎。不同的引擎对同一个样式的实现不一致,就导致浏览器的兼容性问题。
2、JS引擎:js引擎可以说是js虚拟机,负责解析js代码的解析和执行。通常有以下步骤:

  • 词法解析:将源代码分解位有意义的分词
  • 语法分析:用语法分析器将分词解析成语法树
  • 代码生成:生成机器能运行的代码
  • 代码执行

不同浏览器的js引擎也各不相同,Chrome用的是V8,FireFox用的是SpiderMonkey,Safari用的是JavaScriptCore,IE用的是Chakra。

之所以说js是单线程就是因为浏览器运行时只开启一个js解释器,原因是若有两个线程操作DOM,浏览器就又晕了。

JavaScript是单线程的,但是浏览器不是单线程的。一些I/O操作,定时器的计时和事件监听是由其他线程完成的。

三、消息队列与事件循环

由上面浏览器一篇的介绍可以知道,浏览器中多个线程的合作完成了异步的操作,那么异步的回调函数又是怎样完成执行的呢? 

这就需要了解消息队列和事件循环了。

如上图所示,左边的栈存储的是同步任务,就是那些能立即执行、不耗时的任务,如变量和函数的初始化、事件的绑定等等那些不需要回调函数的操作都可归为这一类。

右边的堆用来存储声明的变量、对象。下面的队列就是消息队列,一旦某个异步任务有了响应就会被推入队列中。如用户的点击事件、浏览器收到服务的响应和setTimeout中待执行的事件,每个异步任务都和回调函数相关联。

JS引擎线程用来执行栈中的同步任务,当所有同步任务执行完毕后,栈被清空,然后读取消息队列中的一个待处理任务,并把相关回调函数压入栈中,单线程开始执行新的同步任务。

JS引擎线程从消息队列中读取任务是不断循环的,每次栈被清空后,都会在消息队列中读取新的任务,如果没有新的任务,就会等待,直到有新的任务,这就叫事件循环。

上图以AJAX异步请求为例,发起异步任务后,由AJAX线程执行耗时的异步操作,而JS引擎线程继续执行堆中的其他同步任务,直到堆中的所有异步任务执行完毕。然后,从消息队列中依次按照顺序取出消息作为一个同步任务在JS引擎线程中执行,那么AJAX的回调函数就会在某一时刻被调用执行。

十四、JS同步异步知识点,重点(Node.js-fs模块补充篇)的更多相关文章

  1. Edge.js:让.NET和Node.js代码比翼齐飞

    通过Edge.js项目,你可以在一个进程中同时运行Node.js和.NET代码.在本文中,我将会论述这个项目背后的动机,并描述Edge.js提供的基本机制.随后将探讨一些Edge.js应用场景,它在这 ...

  2. [Node.js] 01 - How to learn node.js

    基本概念 链接:https://www.zhihu.com/question/47244505/answer/105026648 链接:How to decide when to use Node.j ...

  3. node.js学习(二)--Node.js控制台(REPL)&&Node.js的基础和语法

    1.1.2 Node.js控制台(REPL) Node.js也有自己的虚拟的运行环境:REPL. 我们可以使用它来执行任何的Node.js或者javascript代码.还可以引入模块和使用文件系统. ...

  4. node.js前后台交互示例 -- 使用node.js实现用户注册功能

    node.js环境自行搭建,参考菜鸟教程的node.js就可以. 1 通过ajax提交index.html中form表单 register.html文件如下: <!doctype html> ...

  5. node.js day01学习笔记:认识node.js

    Node.js(JavaScript,everywhere) 1.Node.js 介绍 1.1. 为什么要学习Node.js 企业需求 + 具有服务端开发经验更好 + front-end + back ...

  6. io.js - 兼容 NPM 平台的 Node.js 新分支

    io.js(JavaScript I/O)是兼容 NPM 平台的 Node.js 新分支,由 Node.js 的核心开发者在 Node.js 的基础上,引入更多的 ES6 特性,它的目的是提供更快的和 ...

  7. 【node】fs模块,文件和目录的操作

    检查文件是否存在,查询文件信息 fs.stat() fs.stat('./server.js', function (err, stat) { if (stat && stat.isF ...

  8. node的fs模块使用————node

    node的fs模块使用----node fs模块是调用文件的模块. var fs=require('fs'); //引用模块. //查看文件信息 fs.stat('index.txt',functio ...

  9. js 同步 异步 宏任务 微任务 文章分享

    分享一篇 写的很好的 宏任务 微任务  同步异步的文章 文章原地址: https://juejin.im/post/59e85eebf265da430d571f89 这一次,彻底弄懂 JavaScri ...

随机推荐

  1. windows 安装 mysql 5.7.12

    看着官网文档搞了半天,也不知所已,最后还是搜索了一下,还是中文好懂 1 下载解压部分略... 2 添加环境变量 在path后加上xx盘:/xx目录/mysql-5.7.12-winx64/bin 3 ...

  2. 03-CSS中的选择器

    高级选择器分为: 后代选择器 子代选择器 并集选择器 交集选择器 后代选择器 使用空格表示后代选择器 , 顾名思义  父元素的后代(包括儿子,孙子,重孙子) 中间空格隔开 是后代 .container ...

  3. 从javascript的循环问题来看待闭包本质

    第一次接触这个问题还是在我刚开始学js的时候,当时就是一头雾水,时隔一年多了,突然又想起了这个问题,在这个春气盎然的周末,我就坐下来研究下并把结果和大家分享下: 先看代码:demo.html < ...

  4. sql代码段添加数据

      declare @i int,@index int     set @i=1     set @index=0   while @i<1000000   begin    set @inde ...

  5. NetCore Selfhost,IIShost,Windows Service Host详解(自宿主、宿主在IIS,宿主在Windows Service中)

    第一部分.自托管 一.依赖.Net Core环境 修改 project.json 文件内容,增加发布时需要包含文件的配置内容(NetCore2.0版本不需要任何设置,NetCore2.0开始彻底放弃p ...

  6. 实例解说Linux命令行uniq

    Linux命令uniq的作用是过滤重复部分显示文件内容,这个命令读取输入文件,并比较相邻的行.在正常情况下,第二个及以后更多个重复行将被删去,行比较是根据所用字符集的排序序列进行的.该命令加工后的结果 ...

  7. php 读取和下载execl

    最近用到php 对excel 的操作 下来 小弟为大家 先贴一下自己的代码  有什么补充的 大神们请指点下.感激不尽. 我用的是yii2   yii2中有类 phpexcel 先说说下载吧. 首先下载 ...

  8. 新建tomcat的server服务,在左侧项目浏览处,右键空白的地方,选择new,再选择other选项

    新建tomcat的server服务,在左侧项目浏览处,右键空白的地方,选择new,再选择other选项. 在弹出的窗口中,下拉滚动条找到Server,并单击next按钮. 在弹出的窗口中,找到第一个A ...

  9. CMD指令大全

    命令提示符(CMD)是在OS / 2 , Windows CE与Windows NT平台为基础的操作系统(包括Windows 2000和XP中, Vista中,和Server 2003 )下的“MS- ...

  10. 18-printf(*)的输出格式

    #include <bits/stdc++.h> using namespace std; int main(){ for(int i = 0; i < 26; i++){ cout ...