精读Javascript系列(六)并发编程、 Javascript异步框架

前言

Javascript是非阻塞型单线程事件驱动的语言,故而JS和浏览器API(WebWorker)联合才能实现异步,异步并不是JS核心的一部分。如果接触过C++这类较底层的面向对象语言,就可知JS异步是并发编程的极大幅度简化,JS很完美的将底层封装起来,不需要程序员关注麻烦透顶的细节,只需要几行代码就能实现异步。

或许JS异步真的就是你人生的梦魇,即便是动动手就能实现,却始终没办法用合适的理论去掌握它,以至于常常在一些特殊情形出现遗漏。事实上,你不真正理解异步,你就不可能真正了解Javascript这门语言

本文会涉及大量底层内容,对进阶有些参考性,但是刚接触JS的,选择性的阅读。

注意术语

  1. 本文中所用的术语(例如阻塞同步等)皆是线程级,皆是线程级,皆是线程级(重要的事情说三遍)
  2. 进程层级和线程层级两者有本质上的不同。
  3. 换个角度说,学过系统编程的,请看看程序编程
  4. 零基础赛高!

总之,开始吧。


并发编程

理解异步,就必须要知道什么是异步。不过在此之前,首先要了解什么是并发编程,下面的内容会捎带一些底层知识,对一些概念也做了一些简化,因此详细请参考其他书籍。

首先,术语事件都是指任务, 两个术语都是通用的(事实上许多术语表达的都是同一个意思)

同一时刻,要准备完成(即待处理)两个及两个以上的任务时,就说有多个事件正在发生, 即并发;此时,这些事件就可以说成是并发事件不支持并发的系统在同一时刻只会有一个待处理的任务。

仍然是在同一时刻,必须同时执行两个及两个以上的任务时, 就说有多个事件正在进行(或称作处理)中,即并行。由于并行的前提是有多个并发事件,因此并行编程的前提是支持并发

线程执行任务最小运作单位,简单来说就是一个线程在同一时刻负责处理一个任务。每个线程各自都有一个调用栈(对应于执行栈),并负责处理自己调用栈的任务(确切来说是执行上下文

单核心CPU处理器的计算机上,它只有一个线程,因此在某一时刻只能执行一个任务;处理多个并发事件时,

  • 线程上切割成数个时间片
  • 将这些任务再次分割为数个独立片段(真正的原子级别ATOM),并将它们一一分配到时间片中。
  • 采取的策略是:这个任务执行一些,其他的任务再执行一些,即在单位时间内交替执行任务。由于切换速度极快,因此根本察觉不到任务交替。
  • 不同任务的切换是需要开销的。

画成图就是:
精读Javascript系列(六)并发编程、 Javascript异步框架_第1张图片
但是在多核心处理器中,有多个线程,因此可以同时执行多个任务(即并行啦), 并行可以有效节省任务切换的开销。
即:
精读Javascript系列(六)并发编程、 Javascript异步框架_第2张图片
注意

  • 无论是并发还是并行,所说的都是同一时刻的事情;只是并发所说的事件是未处理的,因此还是停留在发生阶段; 而并行则所说的事件是正在处理的, 已经进入到了执行阶段
  • 一个事件要被处理,首先能够检查到它已经发生。一个未发生的事件是不可能得到处理的
  • 并发相较于并行侧重点在于如何更快处理待处理的事件并考虑如何更快的进行事件切换并行相较于并发侧重点在于如何同时处理正在执行中的事件
  • 高级编程语言中,并发并行两个概念在并发编程中不会做严格区分(确切来讲,并发并行硬件编程领域,哎,那是来自深渊的概念。。。);通俗来讲,我们的并发就是默认并行的。

关于JS:

  • Javascript本身是单线程的,但它支持并发,但是无法并行
  • 正因为如此,JS异步框架也只能是基于单线程的。

好了,并发就这么简单。


线程通信

当一个任务完成前, 可能会使用上一个任务的处理结果。这时就可以说前一个任务依赖于后一个任务。当然,如果任务之间并无依赖,那么各自执行完毕即可。

例如:

  let taskA = (a,b)=>a+b  // 相加 
  let taskB = (a,b)=>a-b  // 相乘
  let taskC = (a,b)=>a*b  // 平方差
  let a = 100, b = 200;
  let res = taskC(taskA(a,b), taskC

你可能感兴趣的:(Javascript学习,javascript,es6,前端)