JavaScript 如何在后台处理 AJAX 响应?
Posted
技术标签:
【中文标题】JavaScript 如何在后台处理 AJAX 响应?【英文标题】:How does JavaScript handle AJAX responses in the background? 【发布时间】:2011-11-26 09:31:52 【问题描述】:由于 javascript 在单线程中运行,在发出 AJAX 请求后,后台实际发生了什么?我想对此有更深入的了解,有人能解释一下吗?
【问题讨论】:
这里有一个很好的描述:***.com/questions/2914161/ajax-multi-threaded JavaScript 代码是单线程的(网络工作者除外),但不是运行 JavaScript 引擎的浏览器... @JuanMendes JavaScript 在一个线程中运行而事件队列在另一个线程中运行吗? @ShaunLuttin 不,事件队列是 JavaScript 的开始 【参考方案1】:在底层,javascript 有一个事件队列。每次 javascript 线程执行完成时,它都会检查队列中是否有另一个事件要处理。如果有,它会将其从队列中拉出并触发该事件(例如鼠标单击)。
位于 ajax 调用下的本机代码网络将知道 ajax 响应何时完成,并且事件将被添加到 javascript 事件队列中。本机代码如何知道 ajax 调用何时完成取决于实现。它可以用线程实现,也可以由事件驱动本身(这并不重要)。实现的重点是,当ajax响应完成后,一些native代码会知道它已经完成,并将一个事件放入JS队列中。
如果当时没有 Javascript 正在运行,则将立即触发该事件,该事件将运行 ajax 响应处理程序。如果当时正在运行某些东西,那么当当前执行的 javascript 线程完成时,将处理该事件。 javascript引擎不需要进行任何轮询。当一段 Javascript 完成执行时,JS 引擎只是检查事件队列以查看是否还有其他需要运行的内容。如果是这样,它会从队列中弹出下一个事件并执行它(调用为该事件注册的一个或多个回调函数)。如果事件队列中没有任何内容,则 JS 解释器有空闲时间(垃圾收集或空闲),直到某个外部代理将其他内容放入事件队列并再次唤醒它。
因为所有外部事件都经过事件队列,并且在 javascript 实际运行其他东西时不会触发任何事件,所以它保持单线程。
这里有一些关于细节的文章:
How Javascript Timers Work - written by John Resig Events and Timing in Depth W3 spec: html5 event loops MDN article on Event Loop Presentation on JS event queue The JavaScript Event Loop: Explained Five Patterns to Help Tame Asynchronous Javascript Javascript Event Loop Presentation Video Discussing How Javascript Works (including event loop at 10:27)【讨论】:
谢谢。我怀疑是这种情况,但很高兴知道这一点。我有一个 for 循环,其中我发送了很多“ajax”请求。在我的处理程序中(对于每个请求——以任意顺序返回)我运行一些可能需要一些时间的代码。很高兴知道这绝对有效。 @telandor - 事件按 FIFO 顺序运行(可能存在一些极端情况例外,但意图是 FIFO)。有些事件的处理方式略有不同。例如 mousemove 事件不会堆积在队列中(可能是因为它们很容易溢出队列)。当鼠标移动并且一个 mousemove 事件已经在队列中并且队列中没有其他更新的事件时,它会更新为最新的位置,而不是添加一个新的事件。我猜想间隔计时器事件可能也被特殊处理以避免它们堆积在队列中。 @telandor - 您需要进一步解释什么?这是先进先出。我在我的答案中添加了一些参考文章。我知道的对 FIFO 的唯一例外是立即触发的事件。您在一个项目上调用.focus()
并触发其他几个事件,例如在具有焦点的项目上的“模糊”事件。该模糊事件是同步发生的,并且不会通过事件队列,因此它会在事件队列中可能存在的其他事情之前立即发生。在实践中,我从未发现这是一个实际问题。
@telandor - 每个浏览器文档没有多个队列。有一个队列,一切都按顺序进行 FIFO 输入/输出。所以超时和 ajax 响应以及鼠标事件和键盘事件都在同一个队列中。无论哪个先进入队列,都会先运行。
@CleanCrispCode - 谢谢。我将其添加为对我的答案的有用参考。【参考方案2】:
您可以找到here 一个非常完整的关于 javascript 事件处理的文档。 它是由一个在 Opera 浏览器中实现 javascript 的人编写的。
更准确地说,看看标题:“事件流”、“事件队列”和“非用户事件”:您会了解到:
-
Javascript 在每个浏览器选项卡或窗口的单个线程中运行。
事件排队并按顺序执行。
XMLHttpRequest 由实现运行,回调使用事件队列运行。
注意:原始链接是:link,但现在已失效。
【讨论】:
【参考方案3】:我想详细说明一下,关于答案中提到的 ajax 实现。
虽然(常规)Javascript 执行是不是多线程的 - 正如上述答案中所指出的 - 然而,
AJAX responses
的真正处理(以及请求处理)是 不是 Javascript,而且它 - 通常 - 是 多线程的。 (请参阅我们将在上面讨论的 XMLHttpRequest 的 chromium source implementation)
我会解释的,我们来看看下面的代码:
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 实现使用 ThreadableLoader go digg-into ?,(您还可以通过查看页面加载的网络选项卡来获得一些印象,您会看到一些同时请求)。
总之,我会说 - 至少 - 您的大多数 I/O 操作可以同时/异步进行(例如,您可以使用 await 来利用这一点)。但所有与这些操作的交互(发布、js 回调执行)都是同步的。
【讨论】:
以上是关于JavaScript 如何在后台处理 AJAX 响应?的主要内容,如果未能解决你的问题,请参考以下文章