co的前世今生(YY篇)
发布于 3 年前 作者 danlanxiaohei 1864 次浏览 来自 分享

co的前世今生(YY篇)

序: 有时候很羡慕大牛,他们的作品简单易用又能解决问题,不过我们往往乐于做一个使用者,而不是发明者,最近在看一些大牛的框架,学习技能的同时,也想揣摩一下他们开发历程,思考一下,是什么激发了他们点子,希望吸取经验,以后自己也写出牛逼的东西。今天我就拿co来举例,臆想一下它的前世今生。


大胆设想

背景:callback以及其导致的金字塔问题

OK,大家都讨厌使用嵌套callback,那么怎么写,才舒服呢?我想最好是可以做到:代码风格是同步的,但执行却是异步的,那么我们先假设我们已经实现了一个这样的框架,叫:wish

那么我们先来使用一下他:

var wish = require('wish');
wish(function () {
  var result1 = async_task1();
  console.log('result1 = ', result1);
  var result2 = async_task2();
  console.log('result2 = ', result2);
})

需求分析

这样还蛮爽的,我们来分析一下需求,我们的核心问题是有几个异步任务,每执行完一个异步任务的时候,就去执行下一个异步任务,直到结束,我们需要实现这样的一个流程控制工具。

OK,现在我们有两个主角,一个是异步任务,一个是任务管理者。管理者负责启动任务,并在他结束的时候,启动下一个任务。

那么现在我们有哪些道具能用呢?

技术选型

首先是异步任务,最好的抽象一个异步任务应该是Promise了,几乎任何一个异步任务都可以封装成Promise,它简直就是一个异步任务的泛型模板。

然后是任务管理者,这个选型就有很多了,可以自己封装一个对象来管理,不过因为Generator的有yield和next,正中下怀。

do it

那么有了Generator和Promise,让我们封装一个wish出来吧。 我们的主旨是,用Generator做流程控制,用Promise做异步任务封装。

function wish(generator) {
  var gen = generator(); // 异步任务管理器
  loop() // 每次执行一个任务

  function loop(res) {
    var ret = gen.next(res)
    if (ret.done) {
      return // 到此结束
    }
    var promise = (ret.value) // 把ret.value封装成promise
    promise.then(loop) // promise完成后,调用loop,执行下一个任务
  }
}

wish(function *(){
  var result1 = yield Promise.resolve('111111');
  console.log('result1=', result1);
  var result2 = yield Promise.resolve('222222');
  console.log('result2=', result2);
})

其实这就是co的最简模型,很简单对吧,带着这个核心思想去看co源码,就容易多了。

3 回复

开始是手动写回调,然后才用的thunk和generator,再promise+generator,现在async+promise。

@i5ting 注释很细致。谢谢

回到顶部