while 循环中的异步函数

2024-01-08

我有一个关于如何在 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 http://blog.victorquinn.com/javascript-promise-while-loop)。虽然这是一个很好的解决方案,但在某些时候,如果循环调用过于频繁,它会遇到堆栈大小问题。

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

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

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

Pedro


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

因此,JavaScript 中不存在不确定或长时间的等待循环。可以循环一秒钟左右,只是为了让时间过去,但这很少有用、高效,也不是编写 JS 代码的最佳方式。

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


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

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
});

如果通知只是一次,那么您还可以使用 Promise,并且 API 只返回一个 Promise,该 Promise 在syncState 更改时得到解决:

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

Promise 的缺点是它们纯粹是一次性使用(仅一个通知),因此如果您想要多个通知,那么最好使用回调。 Promise 相对于回调的优点在于,它们提供了许多用于将它们与其他事件同步的功能(例如排序、等待一系列事件全部完成、协调多个异步事物等),并且它们提供了更好的异步功能错误处理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

while 循环中的异步函数 的相关文章

随机推荐

  • 文件无法使用 PHP fopen 打开

    我试过这个 这应该以只读模式打开文件 但事实并非如此 test txt 文件与 index php 主项目文件夹 位于同一文件夹中 文件打不开 当我把 echo 像这样 echo fileip 它回来了 资源 ID 3 文件确实打开得很好
  • MySQL 事件在一段时间后停止工作

    我有一些游戏 其中用户的健康状况和其他属性每隔几分钟就会使用 MySQL 事件更新一次 我遇到了一个问题 最终事件不再运行 事件中的 SQL 不会被执行 我不确定如何修复它 所以我尝试重新启动 MySQL 这修复了它一段时间 我将 MySQ
  • 如何使 getElementsbyName 适用于 IE(和 FF)?

    这是在 IE 中出错但在 FF 中有效的 JavaScript 错误 document getelementsbyname 0 innerhtml 为 null 或不是对象 var oldVal parseInt document getE
  • JSHint 无法识别 Visual Studio Code (VSCode) 中的 Async/Await 语法

    我一直在努力使用 VSCode 和 JSHint 来找到摆脱这种语法突出显示的方法 JSHint 似乎无法识别 Async Await 语法 在这里您可以找到我正在谈论的内容的屏幕截图 我的 JSHint 版本 jshint esnext
  • 对于新项目,使用本地 gradle 发行版而不是包装器

    我想使用本地 gradle 发行版而不是 gradle 包装器 我将 IntelliJ 用于 Android 项目 为了启动新的 gradle 项目 我会得到一个选项窗口 询问要使用哪个发行版 包装器或本地 而对于 android 项目 我
  • GeoJSON 坐标?

    我有一个 GeoJSON 文件 我正在尝试处理它 以便在谷歌地图上绘制一些特征 然而 问题在于坐标不是传统的纬度 经度表示形式 而是一些大的六 七位数 例子 type FeatureCollection features type Feat
  • 如何从信号中去除频率

    我想从信号中删除一个频率 一个峰值 并在没有它的情况下绘制我的函数 在 fft 之后 我找到了频率和幅度 我不确定现在需要做什么 例如 我想删除我的最高峰 在绘图上用红点标记 import numpy as np import matplo
  • MongoDB:模式迁移、更新或插入

    虽然 MongoDB 不需要任何固定模式 但有时我们希望从一种结构迁移到另一种结构 我最近正在处理一个小数据集 200K 并决定循环现有数据 转换数据模型并插入到新集合中 事实证明 我们的 vps 并没有那么强大 使用 php 驱动程序 在
  • 是否存在可以按任意顺序加密和解密的安全密码算法?

    我正在寻找一种满足以下规则的加密算法 E key1 E key2 消息 E key2 E key1 消息 显然解密也一样 这可能是一个不太可能的事情 因为我怀疑这样的算法是否存在 但认为值得一问 Thanks 具有相同模数的 RSA 可以做
  • 用于 google web 登录的 TypeScript 绑定

    我正在构建一个 angular2 typescript 应用程序 我看到谷歌推出了平台 js https apis google com js platform js它可以访问gapi var 如上所示谷歌登录网站 https develo
  • 无法在 std::map 成员变量中分配具有前向声明值的类

    In test h ifndef TEST H define TEST H include
  • AJAX 请求在大型查询字符串上中止 Elixir Plug

    我在 AJAX 请求中发送 2 个大查询字符串 它们基本上是 jpeg 的 Base64 编码 当相机不是高分辨率相机时 AJAX 请求不会中止 起初 我认为这是 Nginx 的问题 因为我收到错误如下request entity too
  • 领域 NoClassDefFoundError:rx.Observable

    我遇到了 Realm 文档中指出的问题 杰克逊数据绑定 Jackson Databind 是一个用于将 JSON 数据绑定到 Java 类的库 Jackson 使用反射来执行数据绑定 这冲突了 Realm 对 RxJava 的支持 因为 R
  • 奥利奥后台位置更新

    我发现自己对新的背景限制感到困惑 我只是在这里寻求一些清晰度 当应用程序位于前台或在后台运行前台服务时 后台服务就可以正常运行 我懂了 当应用程序在后台且没有前台服务时 后台服务将被系统停止 我对此也很满意 我的问题 该应用程序每小时仍可以
  • 当我进行编程配对时,如何避免或忽略 Android 的蓝牙配对通知?

    我有一个应用程序 可以通过编程方式控制蓝牙配对和取消配对 我可以在连接前配对并在连接后取消配对 我需要这样做的原因是特定于我的应用程序的 而不是在我的问题范围内 基本上我正在做的是 获取参考ib to IBluetooth中描述的对象这个答
  • Makefile 和 $$ 的使用

    所以我有一个 Makefile 其中包含我尝试理解的以下代码 for file exe in find name zip exe do file exe d UNZIP PATH lib done 据我了解 这段代码将尝试找到一些可执行的
  • 删除 Jumbotron Bootstrap 3 中的填充?

    如何从 jumbotron bootstrap 3 中删除默认填充 我正在尝试设置padding top 5px 在大屏幕分区 但是有一些默认的填充 如何删除它 问题是 CSS 选择器对大屏幕的特异性会大于您正在应用的选择器 您可以阅读有关
  • Rails:忽略传递给 create() 的不存在的属性

    我有以下 Rails 模型 class CreateFoo lt ActiveRecord Migration def self up create table foo do t t string a t string b t string
  • 在 x 轴上绘制时间序列时,对 ggplot 中的一个方面使用 annotate("rect")

    我正在各个方面绘制不同的时间序列 并且我想使用 annotate 仅为其中一个方面创建不同的背景颜色 一个方面代表 2018 年的最后 15 周 第 38 52 周 而另一个方面代表 2019 年的前 15 周 第 1 15 周 我只想更改
  • while 循环中的异步函数

    我有一个关于如何在 while 循环中执行异步任务直到满足某些条件的问题 这更多的是一个理论问题 但我可以看到在某些情况下这可能是一个问题 我将尝试通过示例演示该问题 我在这里使用 JavaScript 但您可以使用任何语言 我可以拥有一个