13

John Resig的《Javascript Ninja 的秘密》一书中,他做出了以下断言:

浏览器编程没有什么不同,只是我们的代码不负责运行事件循环和调度事件;浏览器为我们处理。

我们的职责是为浏览器中可能发生的各种事件设置处理程序。这些事件在发生时被放置在一个事件队列(一个 FIFO 列表;稍后会详细介绍)中,并且浏览器通过调用为它们建立的任何处理程序来调度这些事件。

因为这些事件发生在不可预知的时间和不可预知的顺序,我们说事件的处理,以及它们的处理函数的调用,是异步的。

我很难接受这里使用异步这个术语。他真的不是说按时间顺序排列的吗?它们也可能是异步的,但不是出于支持此声明的原因。想法?

4

7 回答 7

3

因为这些事件发生在不可预知的时间和不可预知的顺序,我们说事件的处理,以及它们的处理函数的调用,是异步的。

这是一个善意的谎言;也许有点夸张。然而;

  • 没有明确顺序的事件可能会以不可预知的顺序发生。

    示例:AJAX 请求 - 哪个响应先到达?

  • 具有明确顺序的事件以可预测的顺序发生。

    示例:setTimeout(a); setTimeout(b);-a将在 之前调用b

和一粒盐一起吃,不要做得太多。

于 2013-03-10T02:19:25.433 回答
3

您的问题标题和问题正文似乎在问两个不同的问题。我会尝试解决这两个问题。

身体问题

异步不是 John 创造的术语,甚至不是 JavaScript 特定的术语。它在计算机科学中具有既定的含义。尽管约翰所说的是准确的,但我认为它是不完整的。他正确地解释了为什么我们使用术语异步(词源),但没有解释什么是异步编程。

在计算机科学中,异步意味着暂停执行代码,允许其他(任意)代码在同一线程中运行,并最终恢复暂停的代码。有很多技术可以实现这一点,也有很多方法可以为程序员抽象出来,但它们都具有暂停代码而不是阻塞的特征。这用于避免在等待一些慢速资源(如 HTTP 请求、文件或数据库)时阻塞整个线程。

例如,如果您要发出一个同步HTTP 请求,那么在请求完成之前没有其他 JavaScript 可以运行。因此,任何依赖于 JavaScript 的网页部分都会被冻结。但是,如果您发出异步HTTP 请求,则发出请求的代码可以在等待请求时暂停。这允许其他代码执行。并且在 HTTP 请求完成后,请求代码可以恢复。

John 说异步代码可以发生的原因是任何顺序,因为我们不知道外部资源何时可用。例如,如果您发出两个或多个异步 HTTP 请求,则无法知道请求将以什么顺序完成(因此,代码将恢复的顺序)。

标题问题

浏览器事件是异步的,就像我们的示例 HTTP 请求一样。事实上,在很多方面用户只是作为其他外部资源。用户将在自己的时间做事,与当前正在执行的代码异步。

例如,如果您的代码为页面上按钮的单击事件定义了一个处理程序。您的 JavaScript 代码不会等待用户单击按钮。它为单击处理程序挂起该代码,并在用户单击按钮时稍后执行它。这就是为什么异步编程在 JavaScript 中如此重要的核心。如果您的代码只是阻塞(等待)直到该 HTTP 请求完成,则用户无法单击该按钮。如果您的代码在等待用户单击某些内容时被阻塞,那么您的 HTTP 请求将超时。

最后的想法

在 JavaScript 中,我们通常不会考虑暂停和恢复代码。事实上,您不能只是在正在运行的代码块中间暂停。该块将始终在执行其他任何操作之前完成。相反,我们将回调从我们的代码块中传递出来,以便稍后执行。这些回调可以同时访问原始代码块中的资源(范围)。回调是从原始上下文恢复的内容。

如果您想深入了解 JavaScript 如何管理并发模型和事件循环,这是一个很好的资源。此外,除了回调之外,JavaScript 还为事件循环添加了一些强大的抽象,例如PromisesGenerators。这些值得花一些时间。

于 2016-04-05T20:18:17.803 回答
2

ajax 请求的事件处理与用户发起的事件相同。当您调用 时xhmlhttprequest.open,您将启动一个异步调用,该调用在请求完成时由onreadystatechange事件处理(可能随时发生)。同样,用户可以随时在 DOM 元素上发起事件。

事件的处理及其回调的调用是异步的,但不一定是回调本身。

我也发现这是一个定义:

属于或需要某种形式的计算机控制定时协议,其中特定操作在收到指示(信号)时开始

该信号可能是单击事件或 xmlhttprequest 就绪状态更改。

于 2013-03-10T01:49:41.290 回答
1

它的措辞方式,我认为它在技术上是正确的(你可能不同意)尽管令人困惑。我会用不同的措辞,因为它似乎表明你的 JavaScript 执行调用被抢占了。

它们的处理函数的调用是异步的。

处理程序的调用(由浏览器本身完成,可能是 C 或 C++,而不是 JavaScript)确实是异步发生的,也就是说,还有其他线程将事件添加到队列中,这意味着事件循环被抢占。

他没有说处理程序的执行是异步的。这些保证运行完成并且不会被抢占(被其他 JavaScript)。

我认为困扰你的另一件事是

因为这些事件发生在不可预测的时间和不可预测的顺序,

这并不是说没有事件以可预测的顺序运行,但有些事件确实如此,因此它在技术上也是正确的,但正如您在setTimeout示例中所展示的那样具有误导性。例如:

  • XHR 请求
  • 同一节点上的多个处理程序过去没有保证顺序,但现在有

另请注意,如果您确实触发了合成事件或调用click()元素,则将立即调用其所有处理程序(跳过队列),新事件不会进入队列。

于 2019-11-20T13:38:08.663 回答
0

我相信 Resig 的意思是,UI 事件必须由浏览器异步处理,否则如果在处理其他内容时执行单击,UI 会阻塞。通常,桌面软件通过多线程来解决这个问题。Web 应用程序依赖于 JavaScript,它使用事件循环来实现异步。

于 2013-03-10T01:50:05.130 回答
0

只是偶然发现了这个非常古老的线程,具有非常现代的含义。尽管普遍认为“JavaScript 是单线程的”,但事件触发确实是异步的。

在任何运行 jQuery 的浏览器中测试:

$('body').click(function () { setTimeout(f => alert('foo'), 1000); });
function calltrigger() { $('body').click(); alert('bar'); }
calltrigger();

这做了三件事并证明了这一点:

  1. 将 onClick 事件添加到body, alert('foo') 延迟 1 秒。
  2. 定义一个匿名函数,该函数首先触发 onClick 事件,然后调用 alert('bar')。
  3. 调用匿名函数。

如果函数中的 onClick 事件被阻塞(同步),您会在“bar”警报之前看到“foo”警报。但你没有。onClick 事件是异步触发的,先触发 alert('bar'),然后触发 alert('foo')。

相反,onClick 事件会触发,并且代码会在事件代码完成之前转到第二个警报。

于 2021-09-09T01:29:15.480 回答
-1

JavaScript 是异步的……它会继续处理代码,即使你调用的方法还没有返回……所以是的,那是正确的。这就是异步的定义:不同步......

我得到了你的查询……因为 FIFO……但我认为使用的术语是合适的……因为它的定义与他们所说的完全一致。

于 2013-03-10T01:35:33.673 回答