Warcry mpi
  1. 1 Warcry mpi
  2. 2 Time Bomb Veela
  3. 3 BREAK IN TO BREAK OUT Lyn
  4. 4 Libertus Chen-U
  5. 5 One Last You Jen Bird
  6. 6 Flower Of Life 发热巫女
  7. 7 Last Surprise Lyn
  8. 8 かかってこいよ NakamuraEmi
  9. 9 Life Will Change Lyn
  10. 10 Hypocrite Nush
2017-01-07 20:24:14

异步编程——线程与事件循环

JS最有特点的一方面就在于它能轻易地处理异步编程。作为因互联网而生的语言,必须要求JS能响应用户的点击,按键,鼠标滚动之类的交互行为。但是JS引擎是单线程运行的,就是说浏览器无论在什么时候都只有一个线程在运行JS,那么如何配合浏览器内核处理这些异步事件呢?事实上除了处理JS的线程外,浏览器内核中还存在其他线程共同配合完成工作。我们就从头来说说JS的异步编程。


从操作系统说起

众所周知JS是以单线程方式运行的,说到线程自然就联想到进程。这两个相似的词有什么区别和联系呢?

首先这两个词其实都是操作系统的概念。在操作系统中,进程是分配资源的基本单位。计算机中的计算都要依赖于CPU,如果要执行一段代码,相关需要的资源(内存,文件等)必须就位。那么这些除了CPU之外的资源就构成了这段代码的运行环境,也就是程序上下文。当分配给它的CPU执行时间用完了就得被切换出去等待下一次执行。被切换出去时最后的工作就是保存程序上下文。那么以上这段程序上下文就是一个进程了。

但是进程的颗粒度太大,一个程序的执行必然不可能是一条逻辑,所以必然会有多个程序模块分别实现不同功能来组合成一个大程序。这些不同的模块共享了进程的资源,并且处于同一程序上下文,就是线程了,线程即是独立运行和调度的基本单位


浏览器

1.事件循环

好了,有了进程和线程的了解,我们再说回浏览器。浏览器不是单线程的,它是多线程,多进程的。包括JS引擎线程,界面渲染线程,浏览器事件触发线程等。浏览器中的JS引擎是基于事件驱动的,这里的事件是指浏览器发派的各种任务,可来自于JS引擎,也可来自于其他线程。

JS引擎中的所有同步任务都有一条主线程来执行,形成一个执行栈。当一个异步事件被触发并完成时,浏览器事件触发线程就将这些事件添加到一个事件队列(task queue)里。一旦执行栈中的所有同步任务执行完毕,执行栈任务为空时,系统就会读取事件队列中的事件,如果事件完成则取出异步任务执行,完成后循环该操作。整个运行机制又称事件循环(event loop)。该事件循环机制有以下两个特点:

  • 执行至完成   当某个异步任务执行完成后,其他任务才会被执行。如果一个任务时间过长,那么应用就不能及时处理其他异步任务。
  • 不阻塞 I/O操作通过事件模型和回调函数处理,等待异步结果返回时,仍可处理其他操作。

2.异步非阻塞模型

知道了单线程的JS引擎是通过事件循环实现异步操作之后,我们可以来具体看看整个实现方法了。但在这之前我们先从宏观角度谈谈浏览器中的JS编程模型——异步非阻塞模型。 异步,非阻塞是两个概念,与之相对的是同步,阻塞。

  • 同步与异步 同步与异步是一种消息通信机制。每一次调用必然会有一个返回结果。同步就是在发出调用时,需要调用者主动等待调用的返回值,没有得到值之前就不返回调用。而异步则在调用发出之后立即返回而不返回值。等到被调用者得到返回值后通知调用者取得该值。
  • 阻塞与非阻塞 阻塞与非阻塞是程序等待返回值时的状态,阻塞指得到返回值之前,当前线程被挂起不往下执行。非阻塞则是即使没有得到返回值,也会往下执行。

3.异步实现方法

事件模型

事件可以来源于以上提到的各种线程,例如定时器方法,鼠标按键等。当事件被触发时,就将该事件添加到事件队列然后通过事件循环机制实现异步操作。JS执行是非阻塞的原因即是分出了一条事件触发线程来实现异步操作。

回调模式

首先得区别回调函数和异步函数是两个不同的概念。异步函数是存放于事件触发线程,等待事件完成时存入事件队列然后通过事件循环取出到执行栈执行的函数。回调函数是传入到一个函数,用来补充该函数功能的函数,为什么很多人经常会弄混这两个概念是因为很多异步实现的功能函数都需要回调函数来完善这个功能。比如定时功能函数,需要"定时执行"这个异步事件完成才能利用回调函数具体实现功能。

回调模式比事件模型灵活的多因为使用回调函数串联多个调用会很容易。但当你想要串联多个调用时,你就会陷入复杂代码串联的回调地狱。

在JS中异步调用非常频繁,在多个回调串联的情况下,为了避免进入回调地狱,我们需要追踪他们并进行清理操作。该怎么办呢?为了有效处理这种情况,ES6推出了Promise对象来应对,我将在下文中讲解该对象。

-- EOF --

添加在分类「 前端开发 」下,并被添加 「JavaScript」「Node.js」 标签。