我从一个渲染并生成一系列图像斑点的函数开始。
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(); });
});
}
}
令我惊讶的是,这无法编译,因为&#34;类型Blob
不能分配给Promise<Blob>
类型。&#34;进一步检查显示yield
运算符在异步函数中解包承诺,这样yield promise
在功能上与yield await promise
相同。
yield
运算符为什么这样做?是否有可能从异步迭代器中产生一系列promise;
答案 0 :(得分:2)
要解决yield
运算符的令人惊讶的行为,一种可能性是将promise包装在函数中。
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(); });
});
}
}
我不确定这是不是一个好习惯,但它确实允许调用者安排异步工作。
答案 1 :(得分:2)
出于某种原因,这两个陈述似乎具有相同的效果:
yield await promise
yield promise
第一个语句实际上编译为Javascript中的yield yield __await(promise)
,它按预期工作。我认为这个想法是你应该能够返回迭代的元素或元素的承诺,所以await
不是必需的
根据我对async iterator规范的理解,它应该用于迭代本身是异步的情况,在你的情况下,迭代本身不是异步的,它更像是一个返回交互的异步方法。我会选择:
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(); });
});
}
})();
}
OR
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(); });
})
);
}