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

由于 JavaScript 在单个线程中运行,在发出 AJAX 请求之后,在后台实际发生了什么?我想更深入地了解一下这个问题,有人能透露点什么吗?

24868 次浏览

在底层,javascript 有一个事件队列。每次执行的 javascript 线程结束时,它都会检查队列中是否有其他要处理的事件。如果有的话,它将它从队列中拉出并触发该事件(例如,鼠标单击)。

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

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

因为所有外部事件都通过事件队列,而且当 javascript 实际运行其他内容时不会触发任何事件,所以它保持单线程状态。

下面是一些关于细节的文章:

您可以在 这里中找到关于 javascript 中事件处理的非常完整的文档。
它是由一个在 Opera 浏览器中从事 javascript 实现的人编写的。

更准确地说,看看标题: “事件流”、“事件队列”和“非用户事件”: 你会发现:

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

注意: 原来的链接是: 链接,但现在已经死了。

关于答案中提到的 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和步骤2之后)时,浏览器开始执行: 1的实际工作。格式化 tcp 请求2。打开插座3。发送标题4。握手5。发送6号尸体。等待回复7。读取标题8。所有这些实现通常都是在与 js 代码执行并行的不同线程中运行的。例如,上面提到的 Chromium 实现使用了 < strong > Threadable Loader go digg-into,(您也可以通过查看页面加载的网络选项卡来获得一些印象,您将看到一些同步请求)。

最后,我想说的是,至少大多数 I/O 操作可以同时/异步执行(例如,您可以使用 等待来利用这一点)。但是与这些操作的所有交互(发出操作、 js 回调执行)都是同步的。