Q:你了解异步编程、进程、单线程、多线程吗?

相关定义

Javascript语言将任务的执行模式分红两种:同步(Synchronous)和异步(Asynchronous)。javascript

  1. 同步:一个进程在执行某个请求的时候,若该请求须要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去。
  2. 异步:进程不须要一直等下去,而是继续执行下面的操做,无论其余进程的状态。当有消息返回时系统会通知进程进行处理,这样能够提升执行的效率。
  3. 进程:狭义上,就是正在运行的程序的实例。广义上,进程是一个具备必定独立功能的程序关于某个数据集合的一次运行活动。它是操做系统动态执行的基本单元,在传统的操做系统中,进程既是基本的分配单元,也是基本的执行单元。
  4. 线程:线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位。指运行中的程序的调度单位。
  5. 单线程:单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行。单线程就是进程里只有一个线程。
  6. 多线程:在单个程序中同时运行多个线程完成不一样的工做,称为多线程。

知识点

js是单线程的java

JS运行在浏览器中,是单线程的,每一个window一个JS线程,既然是单线程的,在某个特定的时刻只有特定的代码可以被执行,并阻塞其它的代码。而浏览器是事件驱动的,浏览器中不少行为是异步的,会建立事件并放入执行队列中,JavaScript引擎是单线程处理它的任务队列。当异步事件发生时,鼠标点击事件发生、定时器触发事件发生、XMLHttpRequest完成回调触发等,将他们放入执行队列,等待当前代码执行完成。编程

浏览器不是单线程的promise

虽然JS运行在浏览器中,是单线程的,但浏览器不是单线程的,例如Web kit引擎,可能有以下线程:浏览器

  • JavaScript引擎线程
  • 界面渲染线程
  • 浏览器事件触发线程
  • HTTP请求线程

当一个异步事件发生的时候,它就进入事件队列。浏览器有一个内部大消息循环,Event Loop(事件循环),会轮询事件队列并处理事件。好比,浏览器当前正在忙于处理onclick事件,这时window onSize事件发生了,这个异步事件就被放入事件队列等待处理,只有前面的处理完毕了,空闲了才会执行这个事件。bash

为何JavaScript是单线程的却能让AJAX异步发送和回调请求,为何setTimeout也看起来像是多线程的?多线程

Ajax请求确实是异步的,这请求是由浏览器新开了一个线程请求,事件回调的时候是放入Event loop单线程事件队列等候处理。当浏览器空闲的时候出队列任务被处理,JavaScript引擎始终是单线程运行回调函数、单线程处理它的任务队列。异步

setTimeout(func, 0)神奇在哪儿?那就是告诉js引擎,在0ms之后把func放到主事件队列中,等待当前的代码执行完毕再执行,注意:重点是改变了代码流程,把func的执行放到了主事件队列中。这就是它的神奇之处了。它的用处有三个:模块化

  1. 让浏览器渲染当前的变化(不少浏览器UI render和js执行是放在一个线程中,线程阻塞会致使界面没法更新渲染)
  2. 从新计算script运行时间,即从新判断”script is running too long”这个警告
  3. 改变了执行顺序

详细解释见下一篇文章《巧用setTimeout(func, 0)》。(2017-11-30注:原本想写的,偶然翻到一篇文章《这一次,完全弄懂 JavaScript 执行机制》以为已经写得很好了,就收藏啦(#^.^#))异步编程

异步编程三种方法

一:回调函数

这是异步编程最基本的方法。
假定有两个函数f1和f2,后者等待前者的执行结果。  

 f1();
 f2();复制代码

若是f1是一个很耗时的任务,能够考虑把f2写成f1的回调函数。

 function f1(callback){
    setTimeout(function () {
      // f1的任务代码
      callback();
    }, 1000);
  }复制代码

执行代码就变成下面这样:  

 f1(f2);复制代码

采用这种方式,咱们把同步操做变成了异步操做,f1不会堵塞程序运行。回调函数的优势是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合,流程会很混乱,并且每一个任务只能指定一个回调函数

2、事件监听

另外一种思路是采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。
仍是以f1和f2为例。首先,为f1绑定一个事件(这里采用的jQuery的写法)。

  f1.on('done', f2);复制代码

上面这行代码的意思是,当f1发生done事件,就执行f2。而后,对f1进行改写:

  function f1(){
    setTimeout(function () {
      // f1的任务代码
      f1.trigger('done');
    }, 1000);
  }复制代码

f1.trigger('done')表示,执行完成后,当即触发done事件,从而开始执行f2。
这种方法的优势是比较容易理解,能够绑定多个事件,每一个事件能够指定多个回调函数,并且能够"去耦合",有利于实现模块化。缺点是整个程序都要变成事件驱动型,运行流程会变得很不清晰。

3、Promises对象

Promise 是异步编程的一种解决方案,比传统的解决方案“回调函数”和“事件”——更合理和更强大。它由社区最先提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。Promise 提供统一的 API,各类异步操做均可以用一样的方法进行处理。
基本用法以下:

const promise = new Promise(function(resolve, reject) {
      // ... some code
      if (/* 异步操做成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    });
    promise.then(function(value) {
    // success
    }, function(error) {
     // failure
    });复制代码

下面列出异步操做失败、抓捕异常的另外一种写法

const promise = new Promise(function(resolve, reject) {
  reject(new Error('test'));
});
promise.catch(function(error) {
  console.log(error);
});复制代码

这样写的优势在于,回调函数变成了链式写法,程序的流程能够看得很清楚,能够实现许多强大的功能。
好比,指定多个回调函数等等。

相关文章
相关标签/搜索