ECMA6 generators: yield promise

后端 未结 2 426
不知归路
不知归路 2020-12-09 19:30

As I understand it ECMA6 generators are supposed to be able to yield to a function that returns a promise, eventually returning the resolved/rejected. Making the code read m

相关标签:
2条回答
  • 2020-12-09 20:05

    tl;dr: The promise yielded by the generator has to move the generator forward.


    If you look at first examples in http://davidwalsh.name/async-generators, you will notice that the async function actually moves the iterator forward:

    function request(url) {
        // this is where we're hiding the asynchronicity,
        // away from the main code of our generator
        // `it.next(..)` is the generator's iterator-resume
        // call
        makeAjaxCall( url, function(response){
            it.next( response );               // <--- this is where the magic happens
        } );
        // Note: nothing returned here!
    }
    

    But since you are working with promises, we can improve on that, a little bit. y.next().value returns a promise, and you'd have to listen to that promise. So instead of writing console.log(y.next()), you'd write:

    var promise = y.next().value;
    promise.then(y.next.bind(y)); // or promise.then(function(v) { y.next(v); });
    

    Babel demo

    Of course this not very practical, because now you cannot access the next yielded value and you don't know when the generator will be done. However, you could write a recursive function which takes care of that. That's what runGenerator introduced later in this article takes care of.

    0 讨论(0)
  • 2020-12-09 20:15

    As I understand it ECMA6 generators are supposed to be able to yield to a function that returns a promise, eventually returning the resolved/rejected.

    No, that's not their purpose. ES6 generators are supposed to provide a simple way for writing iterators - each call to a generator function produces an iterator. An iterator is just a sequence of values - like an array, but consumed dynamically and produced lazily.

    Now, generators can be abused for asynchronous control flow, by producing a sequence of promises that is consumed asynchronously and advancing the iterator with the results of each awaited promise. See here for an explanation without promises.

    So what your code is missing is the consumer that actually waits for the promises and advances your generator. Usually you'd use a dedicated library (like co or task.js), or one of the helper functions that many promise libraries provide (Q, Bluebird, when, …), but for the purposes of this answer I'll show a simplified one:

    function run(gf) {
        let g = gf();
        return Promise.resolve(function step(v) {
             var res = g.next(v);
             if (res.done) return res.value;
             return res.value.then(step);
        }());
    }
    

    Now with this function you can actually "execute" your getPromise generator:

    run(getPromise).then(console.log, console.error);
    
    0 讨论(0)
提交回复
热议问题