异步编程之Generator(1)——领略魅力

异步编程系列教程:node

  1. (翻译)异步编程之Promise(1)——初见魅力
  2. 异步编程之Promise(2):探究原理
  3. 异步编程之Promise(3):拓展进阶
  4. 异步编程之Generator(1)——领略魅力
  5. 异步编程之Generator(2)——剖析特性
  6. 异步编程之co——源码分析

为什么使用Generator


回顾一下咱们以前学习的promise。咱们巧妙利用了promise/deferred模式,用链式结构代替了嵌套回调的结构,大大缓解了回调地狱。咱们再来看看以前咱们举的那个异步串行队列的例子吧!假设咱们有一个hello.txt,里面存了一个JSON文件的文件名,咱们须要获得JSON文件的message属性的值。步骤以下:git

  1. 读取hello.txt文件
  2. 获得JSON文件名,再次读取文件
  3. 获得JSON数据后,进行JSON解析
  4. 得到JSON的message属性

Promise链式调用

这个例子咱们以前也是举过很是屡次的,咱们尝试使用Promise链式结构完成:github

//这里的readFile已是promise化的异步API
readFile('hello.txt', 'utf-8')
    .then(function(filename){
        return readFile(filename, 'utf-8');
    })
    .then(JSON.parse)
    .then(function(data){
        console.log(data.message);
    })
    .catch(function(err){
        console.error(err.message);
    });

这样一看下来,promise好像并无多大问题,思惟是线性的,并且错误处理也很友好。咱们只须要把上一层执行后的结果经过then()传到下一步执行便可。嗯,但不得不说被链式结构束缚后,咱们并无获得一种酣畅淋漓的编程体验。编程

同步API

咱们要写的爽,固然是要将异步编程获得同步编程的体验,这样咱们直接使用同步API看一下是怎样的:json

var filename = fs.readFileSync('hello.txt', 'utf-8');
var json = fs.readFileSync(filename, 'utf-8');
console.log(JSON.parse(json).message);

同步的写法清晰明了,并且更符合咱们以往的编程习惯。可是同步API阻塞代码这个弊病会在Javascript的单线程执行中很是明显。咱们到底有没有一种既能够很是接近同步编程的写法,又能够异步不阻塞代码执行呢?既然问出这种问题,答案固然是有的,就是今天的主角:Generatorapi

Generator使用co写法

Generator,顾名思义是一个构造器,它自己是用来生成迭代器的。它是ES6的新东西,因此你为了使用它,须要在node中开启harmony模式才能体验到它。promise

$ node --harmony异步

基于Generator,TJ大神作了一个co库。co在最新的版本里,结合Generator和Promise改善了异步编程的体验,也就是咱们以前说的:既能够同步,又不会阻塞异步编程

仍是同样的例子,咱们结合promise的代码和同步API的代码对比看看:函数

co(function* (){
    var filename = yield readFile('hello.txt', 'utf-8');
    var json = yield readFile(filename, 'utf-8');
    return JSON.parse(json).message;
}).then(console.log, console.error);

很是像有没有,咱们再也不须要将每一次异步的结果都放在then()中进行处理,咱们能够经过相似于同步的写法调用Promise异步API,大大提高编程体验。最后co()返回了一个promise对象,提供咱们作最后的数据处理和错误处理。咱们从同步API转到co,仅仅须要作到如下几点:

  • co里面传的函数标识符须要加上*号,function*。这也就是Generator函数
  • 调用promise异步API以前,都要加上yield标识符
  • 将须要作最后处理的数据return出来,在then()中进行处理便可

预习Generator


咱们在举完异步串行的例子后,此次的文章就接近尾声了。最后咱们能够大体了解一下co究竟是如何运做的呢?咱们会在接下来的文章进行深究,这一次就简单说一说,你看成预习就能够了:

Generator相关

  1. Generator生成迭代器后,等待迭代器的next()指令启动。
  2. 启动迭代器后,代码会运行到yield处中止。并返回一个{value: AnyType, done: Boolean}对象,value是此次执行的结果,done是迭代是否结束。并等待下一次的next()指令。
  3. next()再次启动后。若done属性不为true,则能够继续从上一次中止的地方继续迭代。
  4. 一直重复2,3步骤,直到done为true。

co相关

  1. co内部的迭代器对象是被封装成Promise的。
  2. yield后面跟的必须是一个promise化的异步API,因此next()获得的结果是一个promise对象。
  3. 若迭代没有结束,则co会自动为该异步promise对象的resolve中,增添一个next()。经过前面的异步执行完回调后,再调用next(),使迭代器的代码不断向前执行。
  4. 若迭代结束,则直接调用整个迭代器对象的resolve

总结

或许如今你们看的是只知其一;不知其二,或许很兴奋想知道更多相关的。若仅仅是想学会用co,我想上面的大概已经足够你看了。可是想更深刻,你必须先弄懂promise的原理和Generator的相关特性。最后使用co库必定会驾轻就熟。

接下来,我会先讲一些关于Generator的相关特性,再配合以前说过的promise,深刻到co的源码学习中。

相关文章
相关标签/搜索