如何在生成器函数中使用Promise和setTimeout来创建异步生成器?



我想写一个生成器函数,创建一个异步生成器。生成器应该每次产生一个递延值,每个递延值都通过一个承诺产生。该值和相关的延迟(以毫秒为单位)来自两个不同的数组。

对于所提供的示例代码,期望的行为是一个记录序列,其中target数组中的每个value都以其相关的(相同索引)delaytimeArray开始记录日志,直到target数组的迭代结束。

我尝试使用下面所示的代码,但它只打印出timeArray中的前2个元素,但它不打印所有其他元素,我不确定它是否在timeArray

的前两个时间间隔之后打印它们
let j = 0;
// Array that shows how long after each number printed
// to the console the next value should be printed.
var timeArray = [6, 68, 51, 41, 94, 65, 47, 85, 76, 136];
// Array of numbers that should be printed.
var targets = [9, 10, 8, 7, 9, 7, 7, 9, 9, 7];
let generator = generateSequence();
async function* generateSequence(casiInfluence) {
yield new Promise((resolve, reject) => {
setTimeout(() => resolve(console.log(targetArray[j]), timeArray[j]); console.log(timeArray[j]);
});
}
(async function main() {
for await (var result of generateSequence()) {
console.log(result);
j++;
result = generator.next();
}
}());

您使用let generator = generateSequence()创建了生成器,但是您从未对其进行迭代。

(这是展开的,并使用了更多的变量名,所以更容易阅读):

var timeArray = [6, 68, 51, 41, 94, 65, 47, 85, 76, 136];//Array that shows how long after each number printed to the console the next value should be printed
var targets = [9, 10, 8, 7, 9, 7, 7, 9, 9, 7];//Array of numbers that should be printed
var generator = generateSequence();
( async () => {
for await ( const printNumber of generator ) {
/* Accessing the generator's properties logs to the console, so... 
Nothing to do in this for{} loop. */
}
} )()
async function* generateSequence() {
for ( const i in timeArray ) {
const delay = timeArray[ i ];
const numberToPrint = targets[ i ];
await waitForPrint( numberToPrint, delay );
yield;
}
}
function waitForPrint( text, delay ) {
return new Promise( (resolve,reject) => {
setTimeout(
() => {
console.log( text );
resolve();
},
delay
)
})
}

如果没有生成器,这将更容易:


var timeArray = [6, 68, 51, 41, 94, 65, 47, 85, 76, 136];//Array that shows how long after each number printed to the console the next value should be printed
var targets = [9, 10, 8, 7, 9, 7, 7, 9, 9, 7];//Array of numbers that should be printed

for( let scheduledTimeMS=0, i=0; i<timeArray.length; i++ ) {
const numberToPrint = targets[ i ];
const delay = timeArray[ i ];
scheduledTimeMS += delay;
setTimeout( () => console.log( numberToPrint ), scheduledTimeMS );
}

对于延迟值生成器的每一步,OP都可以实现自己的任务…像…

  • 将OP的数组映射为更好的可处理数据结构…这里是一个元组数组,其中每个元组由…[<value>, <delay>].

  • 将每个值-延迟元组映射为延迟值操作,这是一个异步函数,创建并返回一个承诺,该承诺将在毫秒后解析valuedelay,其中创建异步函数的映射函数称为createDeferredValue

  • 从异步函数数组中创建异步生成器,其中生成器函数名为createPoolOfDeferredValues

// - a specific helper which creates an async function
//   (encapsulating a promise) for each to be deferred value.
function createDeferredValue(value, delay) {
return async function () {
return await (
new Promise(resolve => setTimeout(resolve, delay, value))
);
};
}
// - another helper which creates an async generator
//   from an array of async functions.
async function* createPoolOfDeferredValues(deferredValueList) {
const asyncFunctions = [...deferredValueList];
let asyncFct;
while (asyncFct = asyncFunctions.shift()) {
yield (await asyncFct());
}
}

// - array that defines how long after each to be
//   processed value the next value will be processed.
const valueDelays = [600, 680, 510, 410, 940, 650, 470, 850, 760, 1360];
// - array of to be processed target values.
const targetValues = [9, 10, 8, 7, 9, 7, 7, 9, 9, 7]

// - maps both above OP's arrays into a
//   better processable data-structure.
const targetEntries = targetValues
.map((value, idx) => [value, valueDelays[idx]]);
console.log({ targetEntries });
// - helper task which creates a list of async functions.
const deferredValueList = targetEntries
.map(([value, delay]) =>
createDeferredValue(value, delay)
);
// create an async generator ...
const poolOfDeferredValues =
createPoolOfDeferredValues(deferredValueList);
(async () => {
// ... and iterate over it.
for await (const value of poolOfDeferredValues) {
console.log({ value });
}
})();
console.log('... running ...');
.as-console-wrapper { min-height: 100%!important; top: 0; }

但是,一旦创建了异步函数的列表/数组,我们可以直接使用for...await来迭代它,而不需要绕道使用异步生成器。因此,上面提供的代码简化为…

// - a specific helper which creates an async function
//   (encapsulating a promise) for each to be deferred value.
function createDeferredValue(value, delay) {
return async function () {
return await (
new Promise(resolve => setTimeout(resolve, delay, value))
);
};
}
// - array that defines how long after each to be
//   processed value the next value will be processed.
const valueDelays = [600, 680, 510, 410, 940, 650, 470, 850, 760, 1360];
// - array of to be processed target values.
const targetValues = [9, 10, 8, 7, 9, 7, 7, 9, 9, 7]

// - maps both above OP's arrays into a
//   better processable data-structure.
const targetEntries = targetValues
.map((value, idx) => [value, valueDelays[idx]]);
console.log({ targetEntries });
// - helper task which creates a list of async functions.
const deferredValueList = targetEntries
.map(([value, delay]) =>
createDeferredValue(value, delay)
);
(async () => {
// - iterate the list of async functions by `for...await`.
for await (const deferredValue of deferredValueList) {
const value = await deferredValue();
console.log({ value });
}
})();
console.log('... running ...');
.as-console-wrapper { min-height: 100%!important; top: 0; }

最新更新