涉及异步调用时,如何设置具体的执行顺序?

2024-02-29

我是 JavaScript 世界的新手(2 天!!),我之前唯一的编码经验是 Java,其中语句的执行是按顺序进行的。 我明白,或者至少我读过,JavaScript 是异步的,这意味着如果有一个语句需要很长时间才能执行,则执行下一个语句,而不会阻止第一个语句的程序。 我遇到了回调(实际上很多!!),但我不知道如何使用它们来确定执行顺序。我写了一段代码只是为了了解它是如何完成的,我当然可以使用一些帮助。

console.log("Beginning");

function Test(callback){
   setTimeout(function(callback){
       console.log("Something that takes a lot of time");
   },5000);
   callback();
}

function tstCallBack(){
    console.log("Should come last");
}

Test(tstCallBack);

我想要的是输出显示 -

Beginning
Something that takes a lot of time
Should come last

但我得到的输出是 -

Beginning
Should come last
Something that takes a lot of time

我可以做些什么来按照我想要的方式获得输出吗?


让我们澄清一下您所说的一些事情:

我是 JavaScript 世界的新手(两天!!),也是我之前唯一的编码 经验是在 Java 中执行语句 依次。我明白,或者至少我读过 JavaScript 是异步的,这意味着如果有一个语句需要 执行时间较长,不持有就执行下一条语句 启动第一个语句的程序。

事情不是这样的。给定的函数在设计上要么是异步的,要么是同步的。它与执行需要多长时间完全无关。您可以拥有非常快的异步函数或非常长的同步函数。决定函数是否异步的是它的设计方式。如果它使用异步 I/O 或计时器或任何其他异步基础设施,则至少该函数的某些执行是异步的。这意味着某些函数将稍后完成,而该函数调用之后的某些代码将在异步部分完成之前执行。

我遇到了回调(实际上很多!!),但我不明白它们是如何实现的 可用于确定执行顺序。我写了一段 代码只是为了了解它是如何完成的,我当然可以使用一些 帮助。

回调用于在某些异步操作完成时通知调用代码。这可以用于消耗异步操作的结果,也可以用于执行异步操作完成后想要按顺序运行的下一段代码。

在您的代码示例中,如果您想要所需的序列,则必须在setTimeout()回调,以便在之后调用setTimeout()调用执行,从而为您提供所需的序列。

您还必须删除callback论证setTimeout打回来。该回调未随该参数一起传递,因此声明它是错误的。可以通过闭包直接从父函数访问它,如下所示:

console.log("Beginning");

function Test(callback){
   setTimeout(function(){
       console.log("Something that is asynchronous");
       // call the callback here to indicate to the calling code
       // that the asynchronous operation is now complete
       callback();
   },5000);
   console.log("After Setting Timer");
}

function tstCallBack(){
    console.log("Should come last");
}

Test(tstCallBack);

这将在控制台中生成一个序列:

开始

设置定时器后

异步的东西

应该排在最后


从概念上讲,Javascript 引擎运行单个线程,并且该单个线程使用事件队列。所以,在上面的函数中,这就是发生的情况。

  1. 首先console.log("Beginning");被执行。
  2. Test(tstCallback)叫做。
  3. 作为执行的一部分Test()函数,安排了一个定时器。这会在 JS 引擎内部注册一个计时器。
  4. 中代码的执行Test()继续,console.log("After Setting Timer");被执行,然后该函数完成。
  5. 当前 JS 线程执行完毕,如果事件队列中没有其他内容,则 JS 引擎无事可做,而是等待下一个事件发生。
  6. 一段时间后(定时器设置的 5 秒),内部定时器将触发,并将定时器事件放入 JS 事件队列中。
  7. 由于此时没有其他 JS 执行,因此将定时器事件从事件队列中拉出并执行。这意味着调用为计时器注册的原始回调。
  8. 当定时器回调被调用时,它执行console.log("Something that is asynchronous");线路,然后调用callback().
  9. Your tstCallback然后调用函数并且console.log("Should come last");被执行。
  10. 异步事件完成执行,JS 引擎查看事件队列中是否还有更多事件。如果是,则将下一个事件从队列中拉出并运行。

关于 Javascript 如何处理异步操作,有许多非常好的参考资料:

JavaScript 如何在后台处理 AJAX 响应? https://stackoverflow.com/questions/7575589/how-does-javascript-handle-ajax-responses-in-the-background/7575649#7575649

JavaScript 定时器如何工作 http://ejohn.org/blog/how-javascript-timers-work/

我是否需要关心异步 Javascript 的竞争条件? https://stackoverflow.com/questions/7238586/do-i-need-to-be-concerned-with-race-conditions-with-asynchronous-javascript/7238663#7238663

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

涉及异步调用时,如何设置具体的执行顺序? 的相关文章

随机推荐

  • pandoc 在转换为 pdf 时不会对代码块进行文本换行

    我正在使用 pandoc 和 xelatex 引擎将 markdown 转换为 pdf 我像这样运行 pandoc pandoc s backbone fundamentals md o backbone fundamentals pdf
  • SpecFlow - 重试失败的测试

    有没有办法实现AfterScenario在失败的情况下重新运行当前测试的钩子 像这样的东西 AfterScenario retry public void Retry if ScenarioContext Current TestError
  • 当 C 表达式中发生整数溢出时会发生什么?

    我有以下 C 代码 uint8 t firstValue 111 uint8 t secondValue 145 uint16 t temp firstValue secondValue if temp gt 0xFF return tru
  • 在 drools-camel-server 上重新加载远程 drools guvnor 资源

    我正在使用 drools camel server 5 4 Final 来执行从 jboss AS7 上的 guvnor 获取的规则 如下所示
  • 如何清除字符串流变量?

    我已经尝试过几件事了 std stringstream m m empty m clear 两者都不起作用 对于所有标准库类型的成员函数empty 是一个查询 而不是一个命令 即它的意思是 你是空的吗 而不是 请扔掉你的东西 The cle
  • 列名作为 PL/SQL ORACLE 中的变量

    我想要一个代码 其中我将列名声明为变量 然后使用此变量从某个表中检索所需的列 DECLARE col n VARCHAR 100 X BEGIN select col n from my table END Oracle 中最简单 最明确的
  • 确定 Ravenscar 程序中堆栈使用情况的最佳实践

    我正在使用 Ravenscar 子集编写一个 Ada 程序 因此 我知道执行时正在运行的任务数量 该代码是由 gcc 编译的 fstack check https gcc gnu org onlinedocs gnat ugn Stack
  • 使用 SQL Server 2012 生成包含一天中各小时的日历表

    问题陈述 我在消防部门工作 正在对我的数据进行统计分析 一个问题是生成一个日历年中每天每小时的服务呼叫数量 我需要一张可以连接到一年中每一天和每天每小时的火灾事件的表 我希望的是以下内容 使用军事时间 2017 年 1 月 1 日 00 0
  • 如何隐藏任务栏条目但保留窗口窗体?

    我想隐藏任务栏条目以最大化有效空间 因为该应用程序有一个系统托盘图标 我不需要任务栏条目 该应用程序不允许您只有一个系统托盘而不是两者都有 如何隐藏任务栏条目但保留窗口窗体 您的申请是用什么语言编写的 你想要的API调用被称为设置窗口长度
  • 删除 UIPopoverPresentationController 后面的调光视图

    我正在尝试删除使用 UIPopoverPresentationController 呈现的弹出窗口后面的变暗视图 我已经实现了自定义 UIPopoverBackgroundView 但似乎没有办法摆脱这种变暗视图 我已经使用视图层次结构检查
  • initializer_list c++11 中的求值顺序

    在下面的代码中是否需要f1之前被调用f2 或反之亦然 还是未指定 int f1 int f2 std initializer list
  • 在 Python 列表推导式中缓存值

    我正在使用以下列表理解 resources obj get file for obj in iterator if obj get file None 有没有办法 缓存 obj get file 当它在 if 语句中检查时 这样就不必调用g
  • 使用 Google OAuth 2.0 的 Nginx 代理

    我有一个 Ubuntu 14 04 服务器 并且有一个运行在以下位置的流星应用程序localhost 3000在此服务器上 我的服务器的公共 FQDN 是sub example com Meteor 应用程序使用 Google OAuth
  • 窗口调整大小指令

    我试图在窗口调整大小时调整 div 大小 环顾四周后 似乎使用指令是最好的解决方案 模板 div div 指示 myApp directive elheightresize window function window return lin
  • 如何编辑 WKWebView 显示的键盘附件视图?

    我在 Swift 应用程序中使用 WKWebView 来呈现一些文本字段 我设置了一些外观属性来匹配特定的设计 在这种情况下 其背景必须是蓝色的 但是当 WKWebView 触发键盘时 它会对外观属性执行一些操作 并以我的颜色的浅色外观显示
  • Python 多处理管道非常慢(>100ms)

    我目前正在用 Python 3 x 编写一个图像处理程序 需要以低延迟 目前 我正在使用管道向子进程发送命令 最重要的是在框架更新时通知它们 在测量父级的 send 命令和子级的 receive 命令之间的时间时 延迟始终 gt 100 毫
  • 将 HTML 返回到 AJAX Rails 调用

    读完大卫 海涅迈尔 汉森之后博客文章 https 37signals com svn posts 3697 server generated javascript responses关于服务器生成的 javascript 我决定回顾一下在
  • 将表达式传递给 NHibernate 中的方法会导致“ConstantExpression”类型的对象无法转换为“LambdaExpression”类型

    这个问题在 NHibernate 2 和 3 中都会出现 我有一个类 A 它有一个类 B 的成员集 直接查询类可以很好地执行 但是当我将涉及类 B 的表达式之一传递到方法中时 出现以下错误 System ArgumentException
  • Airflow - 分支连接运算符

    我正在尝试加入 Airflow 中的分支操作员 我这样做了 op1 gt gt op2 op3 op4 op2 gt gt op5 op3 gt gt op6 op4 gt gt op7 op5 op6 op7 gt gt op8 它给出了
  • 涉及异步调用时,如何设置具体的执行顺序?

    我是 JavaScript 世界的新手 2 天 我之前唯一的编码经验是 Java 其中语句的执行是按顺序进行的 我明白 或者至少我读过 JavaScript 是异步的 这意味着如果有一个语句需要很长时间才能执行 则执行下一个语句 而不会阻止