2011-07-12 66 views

回答

56

假设,然后,其他一些JavaScript方法称为myFunction被调用我的页面上时myCallback是异步调用。

一个操作优先于另一个吗?他们是否都在同一时间运行?怎么了?

浏览器上的JavaScript是单线程的(禁止使用web workers,而且语法明确)。所以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事件。由于我的处理程序尚未附加,因此我无法接听电话,因为当我附加了处理程序时,该事件已经被解雇。

但是你可以看到排队的效果,如果我们扭转这些行:设置src

var img = document.createElement('img'); 
img.onload = function() { 
    // Handle the fact the image loaded 
    foo(); 
}; 
img.src = /* ...the URL of the image... */; 
doSomethingElse(); 
doYetAnotherThing(); 

现在我挂钩事件。如果img.src = ...线和doSomethingElse线(因为浏览器在高速缓存中的图像)之间的事件触发,回调到我的处理程序获取排队doSomethingElsedoYetAnotherThing在我的处理程序执行之前运行。只有当控制通过我的代码时,排队调用我的处理程序才能最终运行。 JavaScript代码是单线程的,但环境不是。

您也可以以非明显的方式屈服于主机环境。例如,通过调用alert或其breathren confirmprompt等,这些功能的坚持像疮大拇指,他们是现代的JavaScript,因为他们不是事件驱动;相反,在显示模式窗口时JavaScript执行被暂停。但是bobincehis in-depth discussion here中指出,这并不意味着当模式显示时,其他代码都不会运行。它仍然是单线程的,但是一个线程被暂停在一个地方(通过模式),​​并用于在其他地方运行代码;确实是非常好的区分。 (鲍勃也指出了一些事件处理  —他focus例如  —这似乎打破了这一规则,但它没有他的榜样调用focus,进而调用事件处理程序,然后返回。没什么两样)Bob指出的项目的关键在于,您的代码在主机环境中调用了一些东西,它会消失并执行某些操作(显示模式对话框,触发blurfocus处理程序,等等。)。

alert及其在特定的原因breathren种种污秽的,特别是围绕focusblur,我建议避免他们赞成更现代的技术(也可看约18倍更好)。)

所以这些是答案一开始提到的警告。尤其如果myFunction电话alert,至少在Firefox中的AJAX完成回调得到alert期间(不是大多数其他浏览器它会)上运行。如果你很好奇尝试什么呢,并在alerts和这样的,here's a test page测试setTimeout和Ajax不会发生;你可以扩大测试的范围。

+0

我有一种感觉,浏览器在内部对这种行为使用一个eventloop(如node.js)。如果是这种情况,你可能想谈谈如何eventloops工作。 – Raynos

0

ajax调用与同时。所以当ajax调用成功时,调用回调函数,然后调用myfunction。

+1

虽然大多数情况是正确的,但不幸的是,这个误解了这个问题:'myFunction'完全独立于回调,并且不被调用回电话。 – ninjagecko

0

您可以快速测试此警报('第一个');警报('第二个');在这两个函数中,看看哪个模式弹出窗口首先出现。如果你的代码真的受到这个命令的影响,那么在两者中加入一些条件检查来防止/允许一些东西。原生js的速度与往返于服务器的完整往返速度是截然不同的。除非你有一些javascript在无限循环中运行,否则在其他函数执行期间返回的ajax调用的几率很小。

2

AJAX回调在下一个事件循环中运行。

+1

提及事件循环的+1。许多人不明白系统是如何运作的。也许你可以包含一个链接,解释JavaScript的evented-ness? – tjameson

3

Javascript类单线程见Is JavaScript guaranteed to be single-threaded?。所以答案是NO,你的事件处理程序和你的函数可以同时运行,或者它们可能不运行。

+1

虽然这是一些实现技术上是可行的,程序员应该总是假设一个事件触发模型严格遵守。除此之外的任何事情都会导致疯狂。 – tjameson

-1

当ajax成功并调用myCallback时,它将同步运行。所以myCallback就像其他函数一样,你先调用它会先运行,或者你最后调用它最后运行。他们不会在同一时间运行。

+0

同步是一个有很多奇怪内涵的恐怖词汇。也许这可以解释得更好一点?就像提到队列中的事件是如何依次执行的一样。 – tjameson

+0

@tjameson - 我们在一个特定的主题,我想我可以使用同步。 :)虽然我解释了,谢谢! – dpp

+0

你投了弃权,那么这有什么问题呢? – dpp

7

这些答案都是错误的[编辑:这个答案被张贴时,至少有3-4错]。 XHR事件放入事件队列/池中。当单线程JavaScript线程不忙时,它将从事件池中获取下一个事件,并对其执行操作。其中一个事件是你的XHR“AJAX”请求,它将触发回调,然后执行。这就是所有没有中断的事件驱动系统的工作原理。

编辑:Upvoting乔的答案,链接到Is JavaScript guaranteed to be single-threaded?,并提到了微妙的边缘的情况下。非常丰富。

+0

他们真的*全部*错了吗? – icktoofay

+0

我同意。并非所有都是错误的,但很多都是误导。 @icktoofay,你的回答绝对正确,所以我+你的答案。 Ninjagecko的答案只是更强大一点。 – tjameson

0

AJAX调用是“asyncronous”,这意味着“火了一个电话,让我知道你想让我回电话时,即时通讯做了什么”。

总之

这样:

function DoSomething() { AJAXCall(Callback); } 

... some time passes then ... 

function Callback() { Done(); } 

这些2函数调用之间什么都可能发生,回调仍然会被调用时响应返回因为虽然JavaScript运行是单线程的浏览器将栈调用发生按照某种顺序(可能是他们的订单,但没有保证)。

这是一个耻辱,我只是做拉住我的旧网站,因为我有做负载几个ajax调用页面的经典例子,因为每个电话回来,将填充页面的各个部分。

尽管每次调用都“附加”到文档加载事件,但一次只能进行1次调用,但服务器可以以任何顺序响应任何调用,因为服务器可能是多线程的(可能是)。

认为JavaScript是一个虚拟框,浏览器可以在其中传递一小块代码,它一次只能运行一次,但它可以按照它认为合适的顺序运行很多脚本(通常这个多个Ajax调用是不可预知的,因为谁知道服务器何时可能会返回结果)

相关问题