这一次终于搞懂 js 异步编程

304 阅读3分钟

简单的小问题

  1. 什么是同步与异步?

在我们学习的传统单线程编程中,程序的运行是同步的(同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序执行)。而异步的概念则是不保证同步的概念,也就是说,一个异步过程的执行将不再与原有的序列有顺序关系。

简单来理解就是:

同步:按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效率更高。

异步:异步就是从主线程发射一个子线程来完成任务。

  1. js是单线程语言,如何用别的线程?谁来执行别的线程?

js是单线程没错,但是js依赖的环境可以是多线程,浏览器和node

例如浏览器的其他线程(不是js) - 操作系统 - cpu等硬件

既往错误的理解:以为异步任务是js后台再执行,执行后再通知主线程。但其实这种是js多线程了

  1. 什么时候使用异步?

通常完成一些耗时的事情,比如读取一个大文件或者发出一个网络请求。因为子线程独立于主线程,所以即使出现阻塞也不会影响主线程的运行。

  1. 异步任务完成后如何通知js线程呢?

涉及:基于回调函数的异步编程,event loop事件循环,代码执行顺序

知识储备

  1. 进程与线程

进程(process):资源管理(资源分配的基本单位) + 线程

线程(thread):操作系统任务调度的最小单位,所谓操作系统的任务调度,实际上的调度对象是线程,⽽进程只是给线程提供了虚拟内存、全局变量等资源。

进程(工厂车间) - 线程(工人)

  • 同一进程不同线程:

共享:虚拟内存(共享相同的地址空间)、全局变量等资源

不共享:私有数据、栈和寄存器等,用于维持自己的、每个线程独立的控制流。

  • 不同进程间的线程:

他们的地址空间是独立的。

进程间的线程通信,交换数据,需要通过操作系统,开销大,过程相对复杂。

所以,线程的上下⽂切换相⽐进程,开销要⼩很多。

  1. js单线程

js是单线程的,js的容器进程是什么?

浏览器 or node

  1. 浏览器环境

多进程,每一进程下多线程

一般来说,new tab 就是一个新的进程。防止相互干扰

除了要运行js代码,还有其他的程序

  1. node环境

image.png 结合上图,Node.js的运行机制如下

(1)V8引擎解析JavaScript脚本。

(2)解析后的代码,调用Node API。

(3)libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎。(libuv是一个多平台的专注于异步IO的库)

(4)V8引擎再将结果返回给用户。

Event Loop

当其中的异步操作完成的时候,会将适合的回调函数添加到异步队列中等待时机执行

image.png

代码执行顺序:

  1. js main script(也可视为宏任务)

  2. 所有微, 一个宏; 所有微, 再一个宏。。。

不同的js运行环境,event loop实现有所区别。 浏览器中的EventLoop是根据HTML5定义的规范来实现的,不同的浏览器可能会有不同的实现,而Node中是由 libuv 实现的。

node中Event Loop中不止包括宏任务和微任务,还有更多细分。

image.png

node中,一次完整的事件循环Tick包括了更多的阶段 :

(详见node官网:nodejs.org/zh-cn/docs/…)

参考

这一次,彻底弄懂 JavaScript 执行机制?:juejin.cn/post/684490…

🌟🌟🌟 异步执行顺序面试题:segmentfault.com/a/119000004…

另外,有任何疑问或者观点不同,欢迎指教~ 大家共同进步!