With ES6 generators, I see code like this:
var trivialGenerator = function *(array) {
var i,item;
for(var i=0; i < array.length; i++){
item = array[i];
yield item;
};
};
Is it possible to write something more like the code below instead?
var trivialGenerator = function *(array) {
array.forEach(function *(item){
yield item;
});
};
I'm asking because the classic for
loop is an abomination.
No, you can't use yield
inside of the inner function. But in your case you don't need it. You can always use for-of
loop instead of forEach
method. It will look much prettier, and you can use continue
, break
, yield
inside it:
var trivialGenerator = function *(array) {
for (var item of array) {
// some item manipulation
yield item;
}
}
You can use for-of
if you have some manipulations with item inside it. Otherwise you absolutely don't need to create this generator, as array
has iterator
interface natively.
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