在脚本执行过程中,当AJAX调用返回时,JavaScript中会发生什么
What happens in JavaScript when an AJAX call returns while the script is executing?
假设我编写了一些JavaScript,使用myCallback
作为AJAX调用的回调方法,在AJAX成功时执行。
假设当myCallback
被异步调用时,在我的页面上调用了其他一些名为myFunction
的JavaScript方法。
一个操作是否优先于另一个操作?它们会同时运行吗?会发生什么呢?
假设当
myCallback
被异步调用时,在我的页面上调用了其他一些称为myFunction
的JavaScript方法。一个操作是否优先于另一个操作?它们会同时运行吗?会发生什么呢?
浏览器上的JavaScript是单线程的(禁止你使用web worker,其语法是显式的)。所以myFunction
将运行,直到它返回-与某些警告(继续阅读)。如果ajax层在 myFunction
运行时(很有可能)完成了一个操作,并且需要调用回调,那么该调用将进入队列。下次代码产生时,将触发队列中的下一个调用。
那么,我们似乎永远不必担心竞态条件。这基本上是对的,但也有微妙之处。例如,考虑以下代码:
var img = document.createElement('img');
img.src = /* ...the URL of the image... */;
img.onload = function() {
// Handle the fact the image loaded
foo();
};
doSomethingElse();
doYetAnotherThing();
由于浏览器上的JavaScript是单线程的,我保证在图像加载时获得load
事件,对吗?
是错误的。JavaScript代码是单线程的,但环境的其余部分可能不是。因此,在设置了img.src
之后,浏览器可能会看到它有一个可以使用的图像的缓存副本,因此它会触发img
上的img.src = ...
行和img.onload = ...
行之间的load
事件。因为我的处理程序还没有被附加,所以我没有得到调用,因为当我附加了我的处理程序时,事件已经触发了。
但是你可以看到排队的效果,如果我们把这些行倒过来:
var img = document.createElement('img');
img.onload = function() {
// Handle the fact the image loaded
foo();
};
img.src = /* ...the URL of the image... */;
doSomethingElse();
doYetAnotherThing();
现在我在设置src
之前挂钩事件。如果事件在img.src = ...
行和doSomethingElse
行之间触发(因为浏览器在缓存中有图像),则对处理程序的回调将排队。doSomethingElse
和doYetAnotherThing
在我的处理程序之前运行。只有当控制从我的代码中传递出去时,对处理程序的队列调用才最终运行。JavaScript代码是单线程的,但环境不是。
您还可以以不明显的方式屈服于主机环境。例如,通过调用alert
或它的兄弟confirm
、prompt
等。这些函数在现代JavaScript中很显眼,因为它们不是事件驱动的;相反,在显示模态窗口时暂停JavaScript执行。但正如bobince在他的深入讨论中指出的那样,这并不意味着在显示模态时其他代码都不会运行。它仍然是单线程的,但一个线程被挂起在一个地方(通过模态),并用于运行代码在其他地方的同时;这确实是一个非常细微的区别。(Bob还指出了一些事件处理-他的focus
示例-似乎打破了这一规则,但它没有。他的示例调用 focus
,后者依次调用事件处理程序,然后返回;这和你调用自己的函数没什么不同。)Bob指出的项目的关键共同点是,你的代码调用了主机环境中的一些东西,这些东西会消失并做一些事情(显示一个模态对话框,触发blur
和focus
处理程序,等等)。
(alert
和它的兄弟会引起各种各样的麻烦,特别是在focus
和blur
周围,我建议避免使用它们,以支持更现代的技术(也可以看起来更好18倍)。
这些就是答案开头提到的注意事项。特别是,如果myFunction
调用alert
,至少在Firefox上ajax完成回调将在alert
期间运行(在大多数其他浏览器上不会)。如果你想知道在alerts
期间会发生什么,不会发生什么,这里有一个测试setTimeout
和ajax的测试页面;你可以进一步扩展测试。
这些答案都是错误的[编辑:当这个答案发布时至少有3-4个错误]。XHR事件放在事件队列/池中。当单线程javascript线程不忙时,它将从事件池中抓取下一个事件,并对它们进行处理。其中一个事件将是您的XHR"AJAX"请求,它将触发回调,然后执行回调。这就是所有没有中断的事件驱动系统的工作方式。
edit: Upvoting Joe的答案链接到JavaScript保证是单线程的吗?并提到了微妙的边缘情况。非常丰富。
Javascript类型的单线程参见Javascript保证是单线程的吗?所以答案是否定的,你的事件处理程序和你的函数可以在同一时间运行,或者他们可能不会。
AJAX回调将在下一个事件循环中运行。
同时调用。因此,当ajax调用成功时,将调用回调函数,从而调用myfunction。
您可以通过添加alert('first one')来快速测试这一点;alert('第二个');在这两个函数中,看看哪个模态弹出先出现。如果您的代码确实受到顺序的影响,请在其中添加一些条件检查以防止/允许某些事情。原生js的速度与往返服务器的速度是完全不同的。除非在无限循环中运行一些javascript,否则在执行其他函数期间返回ajax调用的几率很小。
AJAX调用是"异步的",这意味着"触发一个调用,让我知道你想让我在我完成后回叫什么"。
so简而言之:
function DoSomething() { AJAXCall(Callback); }
... some time passes then ...
function Callback() { Done(); }
在这两个函数调用之间任何事情都可能发生,当响应返回时回调仍然会被调用,因为尽管javascript运行时是单线程的,浏览器将以某种顺序堆叠调用(可能是它们的顺序,但不保证)。
很遗憾,我刚刚完成了我的旧网站,因为我有一个经典的例子,一个页面在加载时进行了几个ajax调用,当每个调用返回时,它将填充页面的各个部分。
虽然每个调用都"附加"到文档加载事件,但一次只能进行一个调用,但是服务器可以以任何顺序响应任何调用,因为服务器可以是多线程的(很可能是)。
把javascript想象成一个虚拟的盒子,浏览器可以在其中传递一小块代码,它一次只能运行一个块,但它可以以任何它认为合适的顺序运行大量脚本(通常这是不可预测的多个ajax调用,因为谁知道什么时候服务器可能会返回结果)
当ajax成功调用myCallback
时,它将同步运行。所以myCallback
和其他函数一样,你先调用它它会先运行或者你最后调用它它会最后运行。他们不会同时跑。
- 同时使用回退和 JavaScript.什么是正确的方法
- 简单的Javascript什么都不做,控制台中没有错误
- Javascript:什么是工厂
- JavaScript什么时候初始化变量
- JavaScript:什么是 NaN、Object 或 Primitive
- Javascript 什么是在三元表达式中确保值“true”的最佳方法
- Javascript 什么是参数中的“索引”
- Javascript什么时候打破MVC模式
- Javascript什么是“'+aStringVarible+'"(双引号加单引号)做
- Javascript:什么等于未定义?为什么不't myVar==未定义的工作
- Javascript什么都不做
- Javascript:什么是多级原型层次结构,为什么我们应该避免它
- Javascript:什么's冒号操作符变量名
- JavaScript:什么会崩溃,什么会崩溃
- Javascript:什么查找更快:数组.indexOf vs对象哈希值
- Rails特定于页面的JavaScript:什么是最佳实践?
- Javascript:什么是函数属性,它的意义是什么?
- Javascript什么都不做
- JAVASCRIPT:什么是";这个";关键字在下面的原型模式(Phaser框架)中引用
- JavaScript:什么是“;空隙0”;意思是