Can I yield from an inner function?

后端 未结 2 1687
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-31 03:46

With ES6 generators, I see code like this:

var trivialGenerator = function *(array) {
    var i,item;
    for(var i=0; i < array.length; i++){
        item =          


        
2条回答
  •  抹茶落季
    2021-01-31 04:35

    No, you can't yield from a callback (technically, it's not an "inner function", which means something else). There's obviously no way to call forEach with the equivalent of *, or, if the callback itself is a generator, to tell forEach to invoke the callback with yield *.

    One alternative is to write a function forEachGen, as follows:

    function *forEachGen(array, fn) { for (var i of array) yield *fn(i); }
    

    essentially moving the for-loop into forEachGen. Defining a little sample generator as

    function *yieldSelf(item) { yield item; }
    

    forEachGen would be used as

    yield *forEachGen(array, yieldSelf);
    

    This assumes the callback is a generator itself, as you seem to imply you want in your example. If the callback were a ROF (regular old function), such as

    function returnSelf(item) { return item; }
    

    Then it would be

    function *forEachGen(array, fn) { for (var i of array) yield fn(i); }
    

    used as

    yield *forEachGen(array, returnSelf);
    

    If you don't mind adding this to the array prototype, then

    Object.defineProperty(Array.prototype, 'forEachGen', { value :
        function *(fn) { for (i of this) yield fn(i); }
    });
    

    then do

    yield *array.forEachGen(yieldSelf)
    

    You may be interested in http://fitzgen.github.io/wu.js/, which defines a wrapper for generators with methods such as forEach on the wrapper.

    async / await

    With await, you should be able to do the following.

    Define a trivial callback which just returns a promise for itself.

    async function returnSelf(item) { return await item; }
    

    forEachAsync maps the input array into an array of promises, and uses await * to create and return a promise for all the individual promises being ready.

    async function forEachAsync(values, fn) {
      return await *values.map(returnSelf);
    }
    

    We can treat the result as a regular promise and print it out in a then:

    forEachAsync([1,2,3], returnSelf) .
      then(result => console.log(result);
    

    or use a little IIFE async wrapper to do wait for the result and then print it out:

    (async function() { 
        console.log(await forEachAsync([1,2,3], returnSelf));
    })();
    

    Tested using

    babel-node --experimental test.js
    

提交回复
热议问题