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 循环中的异步函数 的相关文章

  • 如何删除除任何特定 id 之外的元素

    假设有一个父 id 其中包含许多元素 我想删除除一个元素之外的所有元素 ex parent id children not id n remove
  • 如何正确清理来自 AngularJS 控制器的无效输入的表单?

    我有一个 AngularJS 表单 其中包含 除其他字段之外 类型之一url 后者很重要 因为这会强制相应的输入成为有效的 URL 在某些条件下 例如 要关闭具有此类表单的模式对话框 我想以编程方式清除该表单 为此 我实现了方法reset基
  • jQuery .push 到 .get 调用中的数组给出空结果

    谁能告诉我为什么下面给我一个空字符串 当我console log contentArray in the get 回调函数它显示数据 但是当我尝试在下面的代码中执行它时 结果为空 sectionArray contentArray func
  • 在版本 4.4.6 中禁用 ckeditor 上下文菜单

    我在 Rails4 项目中使用 ckeditor 我尝试了 ckeditor gem 和 ckeditor rails gem 来提供 ckeditor 库 这里有多个帖子 人们希望删除 ckeditor 上下文菜单 以便可以显示本机浏览器
  • 通过 JavaScript 获取表单名称

    我有一个简单的问题 但我在网上找不到好的解决方案 我有这个 HTML 代码
  • nodejs (libuv) 事件循环是否在一个阶段(队列)中执行所有回调,然后再进入下一阶段或以循环方式运行?

    我正在研究 Node js 中 libuv 提供的事件循环 我遇到了关注 Deepal Jayasekara 的博客 https blog insiderattack net event loop and the big picture n
  • 如何在网站上使用 svg 元素制作块的屏幕截图?

    我在网站上创建了一个构造函数 其本质是将所选元素及其颜色 svg中的元素 添加到访问者选择的背景和背景颜色 png中的背景 中 然后必须单击 保存 结果 按钮并仅执行工作区的屏幕截图 我写了这个脚本 但它需要屏幕截图 但只有背景 并忽略选定
  • 如何使用 Greasemonkey 监视静态 HTML 页面的更改?使用哈希?

    我希望我的 Greasemonkey 脚本仅在其访问的静态页面具有与以前完全相同的内容时运行 现在我可以设置一个包含该页面哈希的变量 我正在寻找一种动态散列页面的方法 以便我可以将我的散列与生成的散列进行比较 关于如何即时实现散列的任何想法
  • JavaScript 中的 Promise 有什么意义?

    一个承诺是一个 可能现在可用 或将来可用 或永远不可用的值 来源 MDN 假设我有一个想要处理图片的应用程序 图片已加载 例如在算法在后台使用它之后 或某种其他类型的延迟 现在我想检查一下图片是否可以在future 通过使用承诺 而不是回调
  • 如何使用角度材料在具有可扩展行的表格中创建嵌套垫表

    我有以下数据 id c9d5ab1a subdomain wing domain aircraft part id c9d5ab1a info mimetype application json info dependent parent
  • 如何使用 Javascript 设置查询字符串

    有没有办法使用 javascript 设置查询字符串的值 我的页面有一个过滤器列表 单击该列表时 它将更改右侧的页内结果窗格 我正在尝试更新 url 的查询字符串值 因此如果用户离开页面 然后单击 后退 按钮 他们将返回到最后一个过滤器选择
  • 使用 JavaScript 移动页面上的按钮

    我的按钮可以移动 但奇怪的是 我无法弄清楚偏移是否有问题 我希望我的按钮随着鼠标光标移动 但现在它的移动方式不是我想要的 有时它会消失 另外 创建的新按钮是重叠的 我不知道如何解决这个问题并拥有更好的外观 var coorA var coo
  • JavaScript eval("{}") 返回行为?

    根据ECMA 262 规范 http www ecma international org publications files ECMA ST Ecma 262 pdf 以下语句返回1 eval 1 eval 1 eval 1 var a
  • 使用 Javascript 设置 cookie [重复]

    这个问题在这里已经有答案了 我正在尝试构建我的第一个移动应用程序 它需要连接到我的 mysql 数据库并使用 json 返回数据 这很好 目前我有一个登录系统 一旦确定用户名和密码存在 它就会返回一条成功消息 对于下一步 我想在我的页面上使
  • 如何使用 JavaScript 或 jQuery 克隆 HTML 元素的样式对象?

    我正在尝试克隆元素的样式对象 这应该允许我在更改后重置所述元素的样式 例如 el style left 50px curr style left 50px Modify the elements style The cloned style
  • Google Maps API (v3) 添加/更新标记

    编辑 它现在可以工作 但如果用户不允许或没有基于位置的服务 则不会加载 请参阅 jsfiddle 示例接受的答案评论 我已经浏览了一些教程和问题 但我无法安静地理解正在发生的事情 或者在这种情况下 没有发生 当用户单击链接时 我正在加载地图
  • 使用 Enzyme 测试 `React.createRef` api

    我想测试下面的类 它使用React createRef api 不过 快速搜索并没有发现任何这样做的例子 有人成功过吗 我该如何嘲笑裁判 理想情况下我想使用shallow class Main extends React Component
  • 有没有办法使用 ko.observableArray 作为地图?

    有没有办法使用ko observableArray http knockoutjs com documentation observableArrays html像地图 字典一样 例如 var arr ko observableArray
  • 滚动顶部不符合预期

    Note 由于上次忘记奖励而重新开放赏金 A Woff 大师已经给出答案 我想在用户展开某一行时到达该行 这样当最后一个可见行展开时 用户不必向下滚动即可查看内容 I used example tbody on click td green
  • 如何通过索引访问 JSON 对象中的字段

    我知道这不是最好的方法 但我别无选择 我必须通过索引访问 JSONObject 中的项目 访问对象的标准方法是只写this objectName or this objectName 我还找到了一种获取 json 对象内所有字段的方法 fo

随机推荐

  • 文件无法使用 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 但您可以使用任何语言 我可以拥有一个