使用async / await / Promises在JavaScript / TypeScript中实现事件同步原语

时间:2018-04-19 17:19:54

标签: javascript typescript promise async-await

我在TypeScript / JavaScript中有一个漫长而复杂的异步过程,分布在许多库和函数中,当它最终完成接收和处理所有数据时,调用函数processComplete()来表示它已完成:

processComplete(); // Let the program know we're done processing

现在,该功能看起来像这样:

let complete = false;

function processComplete() {
   complete = true;
}

为了确定流程是否完整,其他代码使用超时或process.nextTick并在循环中反复检查complete变量。这是复杂而低效的。

我想让各种async函数只使用await等待并在流程完成时被唤醒:

// This code will appear in many different places
await /* something regarding completion */;
console.log("We're done!");

如果我在C中用Windows编程,我会使用event synchronization primitive,代码看起来像这样:

Event complete;

void processComplete() {
   SetEvent(complete);
}

// Elsewhere, repeated in many different places
WaitForSingleObject(complete, INFINITE);
console.log("We're done!");

在JavaScript或TypeScript中,不是将布尔complete值设置为true,而是processComplete可以做什么来唤醒使用await等待的任意数量的函数?换句话说,如何使用awaitasyncPromise来实现事件同步原语?

3 个答案:

答案 0 :(得分:1)

此模式非常接近您的代码:

const processComplete = args => new Promise(resolve => {
   // ...
   // In the middle of a callback for a async function, etc.: 
     resolve(); // instead of `complete = true;`
   // ...
}));

// elsewhere
await processComplete(args); 
console.log("We're done!");

更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

答案 1 :(得分:1)

这实际上取决于您在此方案中使用“其他代码”的含义。听起来您想要使用delegation patternobserver pattern的某些变体。

一种简单的方法是利用JavaScript允许您存储一系列函数的事实。您的processComplete()方法可以执行以下操作:

function processComplete(){
    arrayOfFunctions.forEach(fn => fn());
}

在其他地方,您可以在其他代码中创建函数,以便在流程完成时完成所需的操作,并将这些函数添加到arrayOfFunctions

如果您不希望这些不同的代码部分如此紧密地连接,您可以设置一个完全独立的代码部分作为通知中心。然后,您可以让其他代码告知通知中心它希望在流程完成时收到通知,并且您的processComplete()方法只会告知通知中心流程已完成。

另一种方法是use promises

答案 2 :(得分:0)

  

我在TypeScript / JavaScript中有一个漫长而复杂的异步过程,分布在许多库和函数中

然后确保异步进程的每个位都返回其部分结果的promise,以便您可以链接到它们并将它们组合在一起或await它们。

  

当它最终完成接收并处理其所有数据时,调用函数processComplete()以表示它已完成

不应该。启动进程的函数应该返回一个promise,当进程完成时,它应该履行这个承诺。

如果你不想正确地宣传整个过程中的每一点,因为它过于繁琐,你可以做到

function startProcess(…);
    … // do whatever you need to do
    return new Promise(resolve => {
        processComplete = resolve;
        // don't forget to reject when the process failed!
    });
}
  

在JavaScript或TypeScript中,不是将布尔complete值设置为true,而是processComplete可以做什么来唤醒使用await等待的任意数量的函数?< / p>

如果他们已经await承诺的结果,那么就没有其他事情需要做了。 (等待的承诺内部已经有这样的旗帜)。它真的只是在做

// somewhere:
var resultPromise = startProcess(…);

// elsewhere:
await resultPromise;
… // the process is completed here

如果你需要的只是同步你的任务,你甚至不需要以有用的结果履行承诺,但你真的应该这样做。 (如果没有他们正在等待的数据,他们还在等什么?)