JavaScript如何在后台处理AJAX响应?


139

由于JavaScript在单个线程中运行,因此在发出AJAX请求后,后台实际发生了什么?我想对此有更深入的了解,有人可以阐明吗?



3
JavaScript代码是单线程的(网络工作者除外),但不是运行JavaScript引擎的浏览器...
Juan Mendes

@JuanMendes JavaScript是否在一个线程中运行,而事件队列在另一个线程中运行?
Shaun Luttin

1
@ShaunLuttin不,事件队列是JavaScript的开始
Juan Mendes

Answers:


213

在幕后,javascript具有事件队列。每次执行javascript线程完成时,它都会检查队列中是否还有其他事件要处理。如果存在,它将退出队列并触发该事件(例如,单击鼠标)。

位于ajax调用下的本机代码网络将知道ajax响应何时完成,并且事件将被添加到javascript事件队列中。本机代码如何知道何时完成ajax调用取决于实现。它可能是用线程实现的,也可能是事件驱动本身的(这并不重要)。实现的重点是,当ajax响应完成时,一些本机代码将知道它已完成并将事件放入JS队列。

如果当时没有运行Javascript,则将立即触发该事件,该事件将运行ajax响应处理程序。如果当时有东西在运行,那么当当前的javascript执行线程完成时,该事件将得到处理。javascript引擎不需要进行任何轮询。当一段Javascript完成执行时,JS引擎仅检查事件队列以查看是否还有其他需要运行的东西。如果是这样,它将弹出队列中的下一个事件并执行它(调用为该事件注册的一个或多个回调函数)。如果事件队列中没有任何内容,则JS解释器将有空闲时间(垃圾回收或空闲),直到某个外部代理将其他内容放入事件队列并再次唤醒为止。

由于所有外部事件都会通过事件队列,并且在javascript实际上正在运行其他事件时不会触发任何事件,因此它保持单线程运行。

以下是有关详细信息的一些文章:


感谢那。我怀疑情况确实如此,但是很高兴知道。我有一个for循环,其中我发出了很多“ ajax”请求。在我的处理程序中(对于每个请求-以任意顺序返回),我运行了一些代码,这可能需要一些时间。很高兴知道这肯定行得通。
iPadDeveloper2011

4
@telandor-事件按FIFO顺序运行(可能存在一些边缘情况例外,但目的是FIFO)。某些事件的处理方式略有不同。例如,mousemove事件不会堆积在队列中(可能是因为它们很容易溢出队列)。当鼠标移动并且mousemove事件已经在队列中并且队列中没有其他新事件时,它将使用最新位置更新,而不是添加新事件。我猜想间隔计时器事件也可能会被特别处理,以避免它们堆积在队列中。
jfriend00 2013年

2
@telandor-您需要进一步解释什么?是FIFO。我在回答中添加了更多参考文章。我知道的对FIFO的唯一执行是立即触发的事件。您调用.focus()一个项目,这会触发其他一些事件,例如具有焦点的项目上的“模糊”事件。该模糊事件是同步发生的,并且不会通过事件队列,因此它会立即在事件队列中可能发生的其他事件之前发生。在实践中,我从未发现这是一个实际问题。
jfriend00 2013年

2
@telandor-每个浏览器文档没有多个队列。只有一个队列,所有内容都按顺序FIFO进/出。因此,超时,ajax响应,鼠标事件和键盘事件都在同一队列中。谁先进入队列,谁先运行。
jfriend00 2013年

1
@CleanCrispCode-Thx。我将其添加为对我的答案的有用参考。
jfriend00 '16

16

您可以在此处找到有关javascript事件处理的非常完整的文档。
它是由致力于Opera浏览器中javascript实现的家伙编写的。

更准确地说,查看标题:“事件流”,“事件队列”和“非用户事件”:您将学到:

  1. Javascript在每个浏览器选项卡或窗口的单个线程中运行。
  2. 事件被排队并顺序执行。
  3. XMLHttpRequest由实现运行,回调使用事件队列运行。

注意:原始链接为:link,但现在已失效。


1

我想详细说明一下答案中提到的ajax实现。

尽管(常规)Javascript执行不是多线程的(如上面的答案中所指出的那样),但是AJAX responses(以及请求处理)的实际处理不是 Javascript,并且通常多线程的。(请参见上文将讨论的XMLHttpRequest的铬源实现

我会解释一下,让我们看下面的代码:

var xhr = new XMLHttpRequest();

var t = Date.now;
xhr.open( "GET", "https://swx.cdn.skype.com/shared/v/1.2.15/SkypeBootstrap.min.js?v="+t(), true );

xhr.onload = function( e ) {
		console.log(t() + ': step 3');
    
    alert(this.response.substr(0,20));
};
console.log(t() + ': step 1');
xhr.send();
console.log(t() + ': step 2');

after an AJAX request is made(-在第1步之后),然后在您的js代码继续执行(第2步及以后)时,浏览器开始以下工作:1.格式化tcp请求2.打开套接字3.发送标头4.握手5.发送正文6.等待响应7.读取标题8.读取正文等。所有此实现通常在与js代码执行并行的其他线程中运行。例如,提到的Chrome实现使用Thheld Loader深入了解😉,(您还可以通过查看页面加载的“网络”标签获得一些印象,还会看到一些同时请求)。

总之,我想说-至少-您的大多数I / O操作可以同时进行/异步进行(例如,您可以通过使用await来利用它)。但是与这些操作的所有交互(发布,js回调执行)都是同步的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.