javascript - while 循环中的异步函数

标签 javascript asynchronous callback theory synchronous

我有一个关于如何在 while 循环中执行异步任务直到满足某些条件的问题。这更像是一个理论问题,但我可以看出在某些情况下这可能是一个问题。

我将尝试在示例中演示问题(我在这里使用 JavaScript,但您可以使用任何语言):

我可以拥有一个设备,我想在该设备达到特定状态之前保留我的应用程序。如果我可以获取设备状态的方法是同步的,则代码可能如下所示:

// Hold until the desired state is reached
var state = false;
while (!state) {
    state = device.getStateSync();
}
// [...] continue the program

我现在的问题是:当我从设备获得的只是一个异步 getState 函数时,我该如何转换这段代码?无论调用的执行时间有多长,代码都应该可以正常工作,并且应该记住我正在处理有限的内存和堆栈大小。

// [...] This would call the async function in a loop and crash the program
while (!state) {
    // [...] something
    device.getStateAsync(function(newState) {
        state = newState;
    });
    // [...] something else
}

我发现的这篇文章有一个递归解决方案 ( http://blog.victorquinn.com/javascript-promise-while-loop )。虽然这是一个很好的解决方案,但如果循环调用过于频繁,在某些时候它会遇到堆栈大小问题。

现在我有直觉,可能没有解决方案。你知道有什么方法可以做到这一点吗?或者你知道如何证明没有办法做到吗?随意包含更复杂的概念,如线程、Promises 或 Futures。

请记住,这是一个理论问题,该示例适用于我无法更改我正在使用的框架(或设备)的情况。

感谢您的每一个回复和想法!

佩德罗

最佳答案

在 javascript 中,您不能循环等待条件更改,除非实际更改条件的代码在该循环内或循环中调用的某个函数的副作用。那是因为 javascript 是单线程的(这里没有考虑的 webworker 除外)所以只要循环在 javascript 中循环,就没有其他代码可以运行,因此没有其他代码可以更改您的条件变量。您将简单地拥有一个无限循环,因为循环等待永远不会改变的东西。最终,浏览器会提示您正在运行无响应的代码并将其关闭。

正因为如此,javascript 中没有不确定或漫长的等待循环。循环一秒钟左右只是为了让一些时间过去是可能的,但这很少有用,也不是编写 JS 代码的最佳方式。

相反,您必须在条件更改时触发事件或回调,并且感兴趣的代码可以订阅该事件或注册其回调。或者,您必须轮询计时器以查看条件发生了什么变化(第一个选项是首选)。


如果您正在设计一个 API,希望能够让一些调用代码知道状态何时发生变化,通常您会实现回调或 promise 。回调方法可能如下所示:

device.registerStateChangeCallback("type of state interested in", fn);

然后,每当指定状态更改为新值时,API 将调用传入的回调函数。这是一次性通知还是每次状态更改时都会发生,直到取消注册回调,这取决于 API。

因此,与其让调用者在繁忙的循环中等待直到状态发生变化,不如调用者编写异步代码(这就是 javascript 处理此类内容的方式),并在稍后状态发生变化时调用回调.例如,调用者的代码可能如下所示:

device.registerStateChangeCallback("syncState", function(newState) {
     // caller puts code here that wants to do something when 
     // the syncState has changed
});

如果通知只发送一次,那么您也可以使用 promises,API 只返回一个 promise,当 syncState 改变时,该 promise 被解决:

device.registerStateChange("syncState").then(function(newState) {
     // caller puts code here that wants to do something when 
     // the syncState has changed
});

promises 的缺点是它们是纯粹的单一用途(只有一个通知)所以如果你想要多个通知,那么最好使用回调。 promises 相对于回调的优势在于,它们提供了很多功能来将它们与其他事件同步(例如排序、等待一系列事件全部完成、协调多个异步事物等),并且它们提供了更好的异步错误处理。

关于javascript - while 循环中的异步函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25335203/

相关文章:

javascript - jQuery:从另一个元素触发悬停事件

javascript - 新手方法 : what is a javascript callback function?

c# - 具有完成事件的异步方法

c# - 异步方法阻塞未等待的任务

javascript - 如何在回调中访问正确的“this”?

c++ - 获取回调函数的地址以在C++中动态调用

javascript - 从字符串调用 javascript 函数

java - 在java中设置cookie,在javascript中读取

javascript - 我需要比较 html 表的行中的数据

asynchronous - Asp.Net Web API, 'async Task' 或 'async void' 作为返回类型