由于 JavaScript 在单线程中运行,因此在发出 AJAX 请求后,后台实际发生了什么?我想对此有更深入的了解,有人可以解释一下吗?
JavaScript 如何在后台处理 AJAX 响应?
在幕后,javascript 有一个事件队列。每次执行的 javascript 线程完成时,它都会检查队列中是否还有另一个事件要处理。如果有,它会将其从队列中拉出并触发该事件(例如鼠标单击)。
位于 ajax 调用下的本机代码网络将知道 ajax 响应何时完成,并且一个事件将被添加到 javascript 事件队列中。本机代码如何知道 ajax 调用何时完成取决于实现。它可能是用线程实现的,也可能是事件驱动本身(这并不重要)。实现的重点是当ajax响应完成时,一些本机代码会知道它已经完成并将一个事件放入JS队列。
如果当时没有 Javascript 正在运行,则将立即触发该事件,该事件将运行 ajax 响应处理程序。如果当时正在运行某些东西,则当当前的 javascript 执行线程完成时,将处理该事件。javascript 引擎不需要进行任何轮询。当一段 Javascript 完成执行时,JS 引擎只会检查事件队列,看看是否还有其他需要运行的东西。如果是,它将从队列中弹出下一个事件并执行它(调用为该事件注册的一个或多个回调函数)。如果事件队列中没有任何内容,则 JS 解释器有空闲时间(垃圾收集或空闲),直到某个外部代理将其他内容放入事件队列并再次唤醒它。
因为所有外部事件都通过事件队列,并且在 javascript 实际运行其他东西时从未触发任何事件,所以它保持单线程。
这里有一些关于细节的文章:
我想详细说明一下,关于答案中提到的 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 代码执行并行。例如,提到的chromium实现使用Threadable Loader go digg-into 😉,(您也可以通过查看页面加载的网络选项卡获得一些印象,您会看到一些并发请求)。
总之,我会说 - 至少 - 您的大部分 I/O 操作可以同时/异步进行(例如,您可以使用await来利用这一点)。但是与这些操作的所有交互(发布、js 回调执行)都是同步的。