我是JavaScript承诺的新手,想知道这是否是在JavaScript / Node.js中异步共享结果的常用/惯用方式。
我有一个方法,比如calc
,它以异步方式计算项目列表。我只希望计算结果一次,其他cals要么得到已计算的结果,要么等到计算结果。我提出了以下设计(一个最简单的例子来演示它)。
let result: Promise<number[]>;
async function calc(): Promise<number[]> {
if (result) {
return result;
}
result = new Promise<number[]>(async (resolve, reject) => {
await delay(5000);
resolve([1, 2, 3, 4, 5]);
});
return result;
}
async function delay(time: number) {
return new Promise<void>((resolve, reject) => setTimeout(resolve, time));
}
这种设计有什么缺陷吗? calc
方法总是异步的吗?即,结果在与调用者不同的堆栈中运行?
答案 0 :(得分:2)
calc
方法总是异步吗?
从promise calc
返回结果将始终是异步的(这可能就是你的意思)。这是由规范保证的:then
和catch
回调总是异步调用,无论承诺是否已经解决。
请注意,如果您要返回一个承诺(您在calc
中的所有代码路径中)并且未在await
的直接正文中使用calc
(您不是t),您无需将calc
声明为async
。这样做在概念上增加了一层承诺(这在很大程度上是无害的,但......)。
这种设计有什么缺陷吗?
一些小的。当然,delay
只是代表你将要做的真正工作。在await delay();
承诺执行者回调中使用async
而没有try
/ catch
意味着如果来自delay
的承诺拒绝。您希望确保处理拒绝(可能在执行程序回调中使用try
/ catch
,或者不在其中使用await
。
与此相关,代码也成为the Promise creation antipattern的牺牲品。由于delay
提供了承诺,因此new Promise
中不需要calc
。只需使用delay
中的那个。
所以calc
可能看起来像这样:
function calc(): Promise<number[]> {
if (result) {
return result;
}
return result = delay(5000).then(() => [1, 2, 3, 4, 5]);
}
由于您明确处理了承诺,我可能不会在其上使用async
。
现场演示(只是为了好玩;我已经延迟了800毫秒而不是5000毫秒):
let result;
function calc() {
if (result) {
return result;
}
return result = delay(800).then(() => [1, 2, 3, 4, 5]);
}
function delay(time) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
console.log("A");
calc().then(() => { console.log("C"); });
console.log("B");
calc().then(() => { console.log("D"); });
setTimeout(() => {
console.log("E");
calc().then(() => { console.log("G"); });
console.log("F");
}, 1000);
如您所见,它输出A B
,等待800毫秒,输出C D
,再等待〜200毫秒,然后输出E F G
,证明消费 calc
的承诺始终是异步的。