使用promises共享异步调用的结果

时间:2017-11-14 10:52:55

标签: javascript asynchronous promise

我是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方法总是异步的吗?即,结果在与调用者不同的堆栈中运行?

1 个答案:

答案 0 :(得分:2)

  

calc方法总是异步吗?

从promise calc返回结果将始终是异步的(这可能就是你的意思)。这是由规范保证的:thencatch回调总是异步调用,无论承诺是否已经解决。

请注意,如果您要返回一个承诺(您在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的承诺始终是异步的。