Future&Hope

koa中的yield

koa中的yield(1)

背景介绍:

  • yield 是es6新出的语法配合Generator一起使用的
  • co是大神Tj写的一套操作一步流程的模块

先看看yield的定义:

由于Generator函数返回的遍历器对象只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield语句就是暂停标志

yield的基本用法就不举例了,说说看有co和没有co的区别吧。举个例子:

function * test() {
  yield 1
  yield 2
}

function * test2() {
  yield 3
  yield test()
  yield 4
}

var b = test2()
b.next() // {value: 3, done: false}
b.next() // Object {value: test, done: false}
b.next() // Object {value: 4, done: false}

此时并没有执行test中的代码,如果想执行test中的方法你可以这样

var b = test2()
b.next() // {value: 3, done: false}
var bb = b.next().value // Object {value: test, done: false}
 bb.next() //bject {value: 1, done: false}

还有一种方法就是:

function * test() {
  yield 1
  yield 2
}

function * test2() {
  yield 3
  yield* test()
  yield 4
}

var b = test2()
undefined
b.next() //Object {value: 3, done: false}
b.next() //Object {value: 1, done: false}
b.next() //Object {value: 2, done: false}
b.next() //Object {value: 4, done: false}

而在koa中,你可以直接这么写

function * test2() {
  yield 3
  yield* test()
  yield 4
}

得到的结果和上面是一样的,这主要是因为koa内部的处理。(后续看一下源码可能会再解释这个问题)

这样看起来是不是已经很好了呢?但是这样有一个问题就是如果test中要执行异步操作,test2不会等到异步操作执行完在执行 yield 4

如果要真的解决异步的问题就需要co的帮助了,具体代码如下:

function *asyncFunction() {
  return new Promise((resolve, reject)=> {
    setTimeout(resolve, 2000, '2000')
  })
}

function *async5000() {
  return new Promise((resolve, reject)=> {
    setTimeout(resolve, 5000, '5000')
  })
}

function *test() {
  var a = yield async5000()
  var b = yield asyncFunction()
  console.log(a)
  console.log(b)
  yield 2
}

co(test)

// 5000
// 2000

co中需要传递一个promise对象或者thunk函数,然后co就会自动调用next函数,co的原理(并不是源码,本段引自阮一峰的es6入门)入:

function run(gen){
  var g = gen();

  function next(data){
    var result = g.next(data);
    if (result.done) return result.value;
    result.value.then(function(data){
      next(data);
    });
  }

  next();
}

run(gen);

就是循环调用next函数,从而达到我们预想的效果。