我可以从内部函数中产生吗?
Can I yield from an inner function?
使用 ES6 生成器,我看到这样的代码:
var trivialGenerator = function *(array) {
var i,item;
for(var i=0; i < array.length; i++){
item = array[i];
yield item;
};
};
是否可以编写更像下面代码的代码?
var trivialGenerator = function *(array) {
array.forEach(function *(item){
yield item;
});
};
我问是因为经典的 for
循环令人厌恶。
不,您不能从回调中退出(从技术上讲,它不是 "inner function",这意味着其他东西)。显然没有办法用 *
的等价物调用 forEach
,或者,如果回调本身是一个生成器,告诉 forEach
用 yield *
调用回调。
另一种方法是写一个函数forEachGen
,如下:
function *forEachGen(array, fn) { for (var i of array) yield *fn(i); }
实质上是将 for 循环移动到 forEachGen
。将一个小样本生成器定义为
function *yieldSelf(item) { yield item; }
forEachGen
将用作
yield *forEachGen(array, yieldSelf);
这假设回调本身就是一个生成器,正如您在示例中暗示的那样。如果回调是 ROF(常规旧函数),例如
function returnSelf(item) { return item; }
那就是
function *forEachGen(array, fn) { for (var i of array) yield fn(i); }
用作
yield *forEachGen(array, returnSelf);
如果您不介意将其添加到数组原型中,那么
Object.defineProperty(Array.prototype, 'forEachGen', { value :
function *(fn) { for (i of this) yield fn(i); }
});
然后做
yield *array.forEachGen(yieldSelf)
您可能对 http://fitzgen.github.io/wu.js/ 感兴趣,它为生成器定义了一个包装器,包装器上有 forEach
等方法。
async
/ await
使用 await
,您应该能够执行以下操作。
定义一个简单的回调,它 return 本身就是一个承诺。
async function returnSelf(item) { return await item; }
forEachAsync
将输入数组映射到一个承诺数组,并使用 await *
创建并 return 准备好所有单独承诺的承诺。
async function forEachAsync(values, fn) {
return await *values.map(returnSelf);
}
我们可以把结果当做一个常规的promise,然后打印出来then
:
forEachAsync([1,2,3], returnSelf) .
then(result => console.log(result);
或者使用一些 IIFE 异步包装器来等待结果然后打印出来:
(async function() {
console.log(await forEachAsync([1,2,3], returnSelf));
})();
使用
测试
babel-node --experimental test.js
不,你不能在其中使用 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
:
var trivialGenerator = function *(array) {
for (var item of array) {
// some item manipulation
yield item;
}
}
如果你对里面的项目有一些操作,你可以使用for-of
。否则你绝对不需要创建这个生成器,因为 array
本身就有 iterator
interface。
使用 ES6 生成器,我看到这样的代码:
var trivialGenerator = function *(array) {
var i,item;
for(var i=0; i < array.length; i++){
item = array[i];
yield item;
};
};
是否可以编写更像下面代码的代码?
var trivialGenerator = function *(array) {
array.forEach(function *(item){
yield item;
});
};
我问是因为经典的 for
循环令人厌恶。
不,您不能从回调中退出(从技术上讲,它不是 "inner function",这意味着其他东西)。显然没有办法用 *
的等价物调用 forEach
,或者,如果回调本身是一个生成器,告诉 forEach
用 yield *
调用回调。
另一种方法是写一个函数forEachGen
,如下:
function *forEachGen(array, fn) { for (var i of array) yield *fn(i); }
实质上是将 for 循环移动到 forEachGen
。将一个小样本生成器定义为
function *yieldSelf(item) { yield item; }
forEachGen
将用作
yield *forEachGen(array, yieldSelf);
这假设回调本身就是一个生成器,正如您在示例中暗示的那样。如果回调是 ROF(常规旧函数),例如
function returnSelf(item) { return item; }
那就是
function *forEachGen(array, fn) { for (var i of array) yield fn(i); }
用作
yield *forEachGen(array, returnSelf);
如果您不介意将其添加到数组原型中,那么
Object.defineProperty(Array.prototype, 'forEachGen', { value :
function *(fn) { for (i of this) yield fn(i); }
});
然后做
yield *array.forEachGen(yieldSelf)
您可能对 http://fitzgen.github.io/wu.js/ 感兴趣,它为生成器定义了一个包装器,包装器上有 forEach
等方法。
async
/ await
使用 await
,您应该能够执行以下操作。
定义一个简单的回调,它 return 本身就是一个承诺。
async function returnSelf(item) { return await item; }
forEachAsync
将输入数组映射到一个承诺数组,并使用 await *
创建并 return 准备好所有单独承诺的承诺。
async function forEachAsync(values, fn) {
return await *values.map(returnSelf);
}
我们可以把结果当做一个常规的promise,然后打印出来then
:
forEachAsync([1,2,3], returnSelf) .
then(result => console.log(result);
或者使用一些 IIFE 异步包装器来等待结果然后打印出来:
(async function() {
console.log(await forEachAsync([1,2,3], returnSelf));
})();
使用
测试babel-node --experimental test.js
不,你不能在其中使用 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
:
var trivialGenerator = function *(array) {
for (var item of array) {
// some item manipulation
yield item;
}
}
如果你对里面的项目有一些操作,你可以使用for-of
。否则你绝对不需要创建这个生成器,因为 array
本身就有 iterator
interface。