JavaScript 异步编程的几种方式比较

1. JavaScript 是单线程,也是多线程的

JavaScript 面向程序员编程,使用的是单线程模型。

 

2. 程序员面向单线程编程,但可以通过执行异步任务避免 CPU 消耗

在程序中处理任务,都会分为同步任务和异步任务。

同步任务,指那些必须要占用 CPU 时间片等待执行结束才能得到返回结果的任务。而异步任务则灵活的多,现实生活中我们处理事情也多采用异步的方式。比如,正在上班突然觉得肚子饿了想要吃东西,那么我们只需要拿出手机点开 App 叫个外卖,然后继续工作。当外卖送达后,我们只需要接收送来的外卖就可以填饱肚子了。此时叫外卖的过程,就相当于执行一个异步任务。执行异步任务时,只需要将执行的信息在某个地方登记并触发相应的资源调用,然后就可以做别的事情了。当任务执行完毕(外卖送达),会通过相关通知机制(送餐员打电话)告诉我们任务执行结束,可以拿到返回值进行下一步操作了。

 

3. JavaScript 异步编程按照规范演进,依次有以下几种方案

a. 回调函数

fs.readFile('/etc/passwd', 'utf-8', function (err, data) {
  if (err) throw err;
  console.log(data);
});

 

b. 事件监听

通过两步操作:将 A方法绑定到某个事件上、执行 B方法触发上一步的事件,从而达到异步 A方法的目的。

 

c. 发布/订阅

通过“注册中心”监听某个信号然后执行 A方法,在 B方法执行后发出与上一步对应的信号,从而触发 A方法的调用。

 

d. Promise 对象

Promise 对象,是通过自身的状态来控制异步操作的,并且一旦状态发生变化就不会再进行更改。

Promise 对象通过构造函数:

var promise = new Promise(function (resolve, reject) {
  // ...

  if (/* 异步操作成功 */){
    resolve(value);
  } else { /* 异步操作失败 */
    reject(new Error());
  }
});

Promise 对象通过原型方法 then 继续后续操作 

var p1 = new Promise(function (resolve, reject) {
  resolve('成功');
});
p1.then(console.log, console.error);

 

e. Generator 函数

Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权(即暂停执行)。整个 Generator 函数就是一个封装的异步任务,或者说是异步任务的容器。异步操作需要暂停的地方,都用yield语句注明。Generator 函数的执行方法如下。

function* gen(x) {
  var y = yield x + 2;
  return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }

Thunk 函数

co 模块

 

f. async 函数

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。async 函数其实就是 Generator 函数的语法糖。

async函数对 Generator 函数的改进,体现在以下四点:

(1)内置执行器

(2)更好的语义

(3)更广的适用性

(4)返回值是 Promise

 

async 注意点:

(1)await 命令后面的 Promise对象结果可能是 rejected,因此需要对此进行捕获,以免错误丢失。

(2)多个 await 的操作,如果互相无逻辑关系,可将多个 await 并发处理:Promise.all

(3)await 只能写在 async 函数中

(4)async 函数可以保留运行堆栈

 

async 函数实现的原理

function spawn(genF) {
  return new Promise(function(resolve, reject) {
    const gen = genF();
    function step(nextF) {
      let next;
      try {
        next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}

 

总结:

Promise 对象、Generator 函数、async 函数三者异步处理方式比较

(1)Promise 的 API(thencatch等等)太多,使得实际逻辑展示不清晰

(2)Generator 函数的执行必须依赖执行器

(3)async 函数实现简介,语句清晰

 

posted @ 2019-06-03 09:38  mykiya  阅读(621)  评论(0编辑  收藏  举报