Getting a promise's value via yield & co

2019-01-25 11:24发布

问题:

I'm trying to figure out how to get the value of a promise via yield, possibly with "co":

function *(){
    var someVar = yield functionThatReturnsAPromise();
}

The called function is not a generator, just a normal function. With the above, someVar == Promise, but I want the resolved value. Does co or some other library have a way of doing this?

回答1:

Yes, co can do that. You'll have to wrap parent function inside co call:

co(function *(){
    var someVar = yield functionThatReturnsAPromise();
})()

someVar inside will become resolved value. If promise gets rejected, error can be cought with basic try {} catch (e) {} statements.



回答2:

Typically a yield acts returns the same value to its own paused execution (left hand side of the yield function) as to the calling function of the generator. In this simple example counting from 1 to 5 example the input of the yield is the output of the yield to the generator function as well as to the generator's execution path:

function* inc() {
    var g = 0; 
    while (true) {
      g = yield g + 1;
    }
}

var incGen = inc();
for (i = incGen.next().value; i <= 5; i = incGen.next(i).value) {
  console.log(i);  //                                ^ input of generator is last output
}

However, the calling function may also call the generator, but replace the output the last yield with another value or even throw an exception to the generator's execution. In the case of promise a function that returns a promise, may yield the result of that promise instead of the promise itself. So in this case:

var someVar = yield functionThatReturnsAPromise();
     ^ output  !=   ^ input

you want the yield to act as a function that takes a promise as an input and returns a resolved promise as an output to the generator function.

It so happens co is able to do exactly this for you. All you need to do is feed your generator function to the co function:

co(function *(){
    var someVar = yield functionThatReturnsAPromise();
})

To better understand how this works, here is an example of a function, that does the same thing as co:

function async(makeGenerator){
  return function (){
    var generator = makeGenerator.apply(this, arguments)

    function handle(result){
      if (result.done) return result.value

      return result.value.then(function (res){
        return handle(generator.next(res))  // <- sets output of yield to the promise result
      }, function (err){                    //    and returns input promise 
        return handle(generator.throw(err)) // <- throw promise exception to generator function
      })
    }

    return handle(generator.next()) // <- first time call, input of yield is a promise
  }
}

source is from Forbes Lindesay's now famous presentation about this concept