当脚本执行时AJAX调用返回时,JavaScript中会发生什么?
假设我写了一些用myCallback
执行AJAX调用的myCallback
作为AJAX成功执行的callback方法。
假设当myCallback
被asynchronous调用时,在我的页面上调用一些其他的JavaScript方法myFunction
被调用。
一个操作优先于另一个吗? 他们都在同一时间吗? 怎么了?
假设当
myCallback
被asynchronous调用时,在我的页面上调用一些其他的JavaScript方法myFunction
被调用。一个操作优先于另一个吗? 他们都在同一时间吗? 怎么了?
浏览器上的JavaScript是单线程的(禁止使用web worker ,并且语法是明确的)。 所以myFunction
将运行,直到它返回 – 有一些警告(继续阅读)。 如果ajax图层在 myFunction
运行时完成一个操作(很可能),并且需要调用callback,那么这个调用会被排队 。 下一次你的代码产生,队列中的下一个呼叫将被触发。
那么,我们似乎就不用担心竞争条件了。 大多数情况是这样,但有一些微妙之处。 例如,考虑这个代码:
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
图像时得到load
事件,对吗?
错误。
JavaScript代码是单线程的,但其余的环境可能不是。 所以可能会发生这样的情况,在设置了img.src
,浏览器可能会看到它有一个可以使用的图像的caching副本,所以它会触发img.src = ...
行之间的img
上的load
事件和img.onload = ...
行。 由于我的处理程序还没有附加,我没有接到电话,因为当我附加我的处理程序,事件已经开除。
但是如果我们颠倒这些线,你可以看到排队的效果:
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
行之间触发(因为浏览器在caching中有图像),则对我的处理程序的callback将被排队 。 doSomethingElse
和doYetAnotherThing
在我的处理程序之前运行。 只有当控制通过我的代码时排队调用我的处理程序终于得到运行。 JavaScript代码是单线程的,但环境不是。
您也可以以非明显的方式屈服于主机环境。 例如,通过调用alert
或其呼吸confirm
, prompt
等等,这些函数就像现代JavaScript中的酸痛拇指一样突出,因为它们不是事件驱动的; 而是显示模式窗口时JavaScript执行被暂停。 但是正如鲍勃在这里深入的讨论中所指出的那样,这并不意味着在模式显示的时候,其他的代码都不会运行。 它仍然是单线程的,但是一个线程暂停在一个地方(通过模式),并用于在其他地方运行代码; 确实是非常好的区别。 (鲍勃也指出了一些事件处理 – 他的focus
范例 – 似乎打破了这个规则,但事实并非如此,他的例子调用 focus
,然后调用事件处理程序,然后返回;与你自己调用函数)。Bob指出的项目的关键在于你的代码已经调用了东西,并且做了一些事情(显示模式对话框,引发blur
和focus
处理等)。
(特别是alert
和气息,会造成各种各样的混乱,特别是focus
和blur
,我build议避免他们倾向于更现代的技术(它也可以看起来更好)。)
所以这些是答案一开始就提到的警告。 特别是,如果myFunction
调用alert
,至less在Firefox上,ajax完成callback将在alert
期间运行(不会在大多数其他浏览器上)。 如果您想要了解在alerts
等情况下是否发生了什么,请setTimeout
testing页面testingsetTimeout
和ajax; 你可以扩展testing去进一步。
这些答案都是错误的[编辑:至less有3-4错误,当这个答案被张贴]。 XHR事件放入事件队列/池中。 当单线程JavaScript线程不忙时,它将从事件池中获取下一个事件,并对其执行操作。 其中一个事件是你的XHR“AJAX”请求,它会触发callback,然后执行。 这就是所有没有中断的事件驱动系统的工作原理。
编辑 :Upvoting乔的回答链接到JavaScript是保证单线程? 并提到微妙的边缘情况。 非常翔实。
JavaScript类单线程看JavaScript是保证单线程? 。 所以答案是否定的,你的事件处理程序和你的函数可以同时运行,否则它们可能不运行。
AJAXcallback在下一个事件循环中运行。
阿贾克斯呼吁同时。 所以当ajax调用成功时,调用callback函数调用myfunction。
您可以通过提醒(“第一个”)来快速testing。 警报(“第二个”); 在这两个函数中,看看哪个模式popup窗口首先出现。 如果你的代码真的受到这个命令的影响,那么在这两个条件中join一些条件检查来防止/允许某些东西 原生js的速度与往返服务器的完整往返速度是截然不同的。 除非你有一些javascript在无限循环中运行,否则在其他函数执行期间返回的ajax调用的几率很小。
AJAX调用是“asynchronous”,意思是“发起一个呼叫,让我知道你要我什么时候回电话”。
总之:
function DoSomething() { AJAXCall(Callback); } ... some time passes then ... function Callback() { Done(); }
在这两个函数调用之间,任何事情都可能发生,当响应返回时,callback仍然会被调用,因为虽然javascript运行时是单线程的,但浏览器将堆栈调用以某种顺序发生(可能是它们的顺序而不是保证)。
这是一个耻辱,我只是拉我完成了我的旧网站,因为我有一个页面的典型例子,加载几个Ajax调用,因为每个调用回来,它会填充页面的各个部分。
尽pipe每个调用被“附加”到文档加载事件中,但是一次只能进行一次调用,但是服务器可以以任何顺序响应任何调用,因为服务器可能是multithreading的(可能是)。
可以认为javascript是一个虚拟框,浏览器可以通过一小块代码,它一次只能运行一次,但它可以按照它认为合适的顺序运行很多脚本(通常这是不可预测的,具有多个ajax调用,因为谁知道服务器何时可能会返回结果)
当ajax成功并调用myCallback
,它将同步运行。 所以myCallback
就像其他的函数一样,你先调用它,或者先调用它,最后再运行。 他们不会在同一时间运行。