i从呈现并产生一系列图像斑点的函数开始。
async function* renderAll(): AsyncIterableIterator<Blob> {
const canvases = await getCanvases();
for (const canvas of canvases) {
yield await new Promise<Blob>((resolve, reject) => {
canvas.toBlob(result => { if (result) resolve(result); else reject(); });
});
}
}
效果很好,但是性能并不理想,因为在开始下一个操作之前,必须解决每个诺言。相反,呼叫者应决定何时等待承诺,同时仍保留订单。
async function* renderAll(): AsyncIterableIterator<Promise<Blob>> {
const canvases = await getCanvases();
for (const canvas of canvases) {
yield new Promise<Blob>((resolve, reject) => {
canvas.toBlob(result => { if (result) resolve(result); else reject(); });
});
}
}
令我惊讶的是,这无法编译,因为"类型Blob
不能分配给类型Promise<Blob>
"。进一步的检查表明,yield
操作员在异步函数中解开承诺,因此yield promise
在功能上与yield await promise
相同。
为什么yield
操作员以这种方式行动?是否可以从异步迭代器产生一系列承诺?
由于某种原因,这两个语句似乎具有相同的效果:
yield await promise
yield promise
第一个语句实际上在JavaScript中编译为yield yield __await(promise)
,该语句按预期工作。我认为您的想法是您应该能够返回迭代的元素或元素的承诺,因此await
不是真正必要的
从我对异步迭代器规范的理解中,应在迭代本身异步的情况下使用它,在您的情况下,迭代本身不是异步,它更像是一种异步的方法,它返回了Intidation。我会选择:
async function renderAll(): Promise<Iterable<Promise<IBlob>>> {
const canvases = await getCanvases();
return (function* () {
for (const canvas of canvases) {
yield new Promise<IBlob>((resolve, reject) => {
canvas.toBlob(result => { if (result) resolve(result); else reject(); });
});
}
})();
}
或
async function renderAll4(): Promise<Iterable<Promise<IBlob>>> {
return (await getCanvases())
.map(canvas => new Promise<IBlob>((resolve, reject) => {
canvas.toBlob(result => { if (result) resolve(result); else reject(); });
})
);
}
要解决yield
操作员的惊人行为,一种可能性是将承诺包裹在功能中。
async function* renderAll(): AsyncIterableIterator<() => Promise<Blob>> {
const canvases = await getCanvases();
for (const canvas of canvases) {
yield () => new Promise<Blob>((resolve, reject) => {
canvas.toBlob(result => { if (result) resolve(result); else reject(); });
});
}
}
我不确定这是否是一个好习惯,但是它确实允许呼叫者安排异步工作。