JS中的协程

##什么是协程 协程其实可以认为是比线程更小的执行单元。线程包含于进程,协程包含于线程。

##协程的优点 协程允许我们写同步代码的逻辑,却做着异步的事,避免了回调嵌套,使得代码逻辑清晰。 我们举一个读取文件的例子:

function *asyncJob() {
  // ...其他代码
  var f = yield readFile(fileA);
  // ...其他代码
}

异步操作是为了避免IO操作阻塞线程。那么协程挂起的时刻应该是当前协程发起异步操作的时候,而唤醒应该在其他协程退出,并且他的异步操作完成时。所以例子中的函数执行顺序如下:

  1. 协程asyncJob开始执行。
  2. 协程A执行到一半,进入暂停,执行权转移到协程readFile。
  3. 协程readFile执行完成后交还执行权。
  4. 协程asyncJob恢复执行。

##协程的实现 JS中有Generator/yield和async/awite实现。 这两者差不多,其实async函数可以看成Generator函数的语法糖。

var fs = require('fs');

var readFile = function (fileName) {
  return new Promise(function (resolve, reject) {
    fs.readFile(fileName, function(error, data) {
      if (error) reject(error);
      resolve(data);
    });
  });
};

var gen = function* (){
  var f1 = yield readFile('/etc/fstab');
  var f2 = yield readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

写成async函数,就是下面这样。

var asyncReadFile = async function (){
  var f1 = await readFile('/etc/fstab');
  var f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};

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

1.内置执行器。async函数自带执行器。也就是说,async函数的执行,与普通函数一模一样。不像Generator函数,需要调用next方法,或者用co模块,才能得到真正执行,得到最后结果。 2.更好的语义。asyncawait,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果。 3.更广的适用性。 co模块约定,yield命令后面只能是Thunk函数或Promise对象,而async函数的await命令后面,可以是Promise对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。 4.返回值是Promise。async函数的返回值是Promise对象,这比Generator函数的返回值是Iterator对象方便多了。你可以用then方法指定下一步的操作。

进一步说,async函数完全可以看作多个异步操作,包装成的一个Promise对象,而await命令就是内部then命令的语法糖。

参考文献: 1.异步操作和Async函数