理解JavaScript中的异步和同步

2022-11-20 11:06:39

1、Javascript语言是一门单线程的语言

单线程和异步确实不能同时成为一个语言的特性。js选择了成为单线程的语言,所以它本身不可能是异步的。因为浏览器只分配给js一个主线程,用来执行那些函数,一次只能执行一个,这些任务形成一个任务队列排队等候执行,但前端的某些任务是非常耗时的,比如网络请求,定时器和事件监听,如果让他们和别的任务一样,都老老实实的排队等待执行的话,执行效率会非常的低,甚至导致页面的假死。

2、JavaScript单线程如何实现异步效果

所以,浏览器为这些耗时任务开辟了另外的线程,主要包括http请求线程浏览器定时触发器浏览器事件触发线程。宿主环境(浏览器)通过事件驱动方式使得js具备了异步的属性 。

所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。

CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。(疑问一)

具体来说,异步运行机制如下:

  1. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  2. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  3. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",那些的异步任务,进入执行栈,开始执行。
  4. 主线程不断重复上面的第三步。

看到第二,三条我就在想 按它文字逻辑,就成了我把那些函数放在任务队列,等我有空了再去执行那个函数,如果我一开始就决定最后做那件事情 就变得跟同步没啥区别了。(疑问二)

3、疑问剖析

贴一些别人博客的描述

所有的程序最终都会由计算机硬件来执行,所以为了更好的理解异步操作的本质,我们有必要了解一下它的硬件基础。 熟悉电脑硬件的朋友肯定对DMA这个词不陌生,硬盘、光驱的技术规格中都有明确DMA的模式指标,其实网卡、声卡、显卡也是有DMA功能的。DMA就是直 接内存访问的意思,也就是说,拥有DMA功能的硬件在和内存进行数据交换的时候可以不消耗CPU资源。只要CPU在发起数据传输时发送一个指令,硬件就开 始自己和内存交换数据,在传输完成之后硬件会触发一个中断来通知操作完成。这些无须消耗CPU时间的I/O操作正是异步操作的硬件基础。所以即使在DOS 这样的单进程(而且无线程概念)系统中也同样可以发起异步的DMA操作。

异步调用并不是要减少线程的开销,它的主要目的是让调用方法的主线程不需要同步等待在这个函数调用上,从而可以让主线程继续执行它下面的代码。与此同时,系统会通过从ThreadPool中取一个线程来执行,帮助我们将我们要写/读的数据发送到网卡。由于不需要我们等待,我们等于同时做了两件事情。 这个效果跟自己另外启动一个线程来执行等待方式的写操作是一样的。但是,异步线程可以利用操作系统/.Net的线程池, 系统可以根据吞吐量动态的管理线程池的大小。

=======================================================================
异步与多线程,从辩证关系上来看,异步和多线程并不时一个同等关系,异步是目的,多线程只是我们实现异步的一个手段。什么是异步:异步是当一个调用请求发送给被调用者,而调用者不用等待其结果的返回。实现异步可以采用多线程技术或则交给另外的进程来处理。

疑问一:CPU占用不高,且IO操作慢,是因为拥有DMA功能的硬件在和内存进行数据交换的时候可以不消耗CPU资源,所以IO操作和CPU是没有关系的。

疑问二:异步的目的是不用等待其结果返回就可以接着往下执行,他和我们自己另启线程来执行的效果是一样的。

4、webWorker

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。

WebWorker的弊端:Worker 线程一旦新建成功就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。

  • 作者:小白啥时候能进阶成功
  • 原文链接:https://blog.csdn.net/qq_34754747/article/details/122880675
    更新时间:2022-11-20 11:06:39