【问题标题】:Are browser events in JavaScript asynchronous?JavaScript 中的浏览器事件是异步的吗?
【发布时间】:2013-03-10 01:30:59
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 也许您应该添加自己对 asynchronous 含义的理解。如果您只是问这本书是否错了,我认为讨论没有建设性。
  • 显然我不是唯一一个对他的“定义”有问题的人,所以我会说这是很有建设性的。
  • @brushleaf,谁这样做谁没有问题并不重要。问题是征求意见、想法和判断。阅读常见问题解答——这完全是一个“不具建设性”的问题。另请注意,有人 在 cmets 中几乎每个答案都在争论——这是主观问题的好兆头。
  • 为了记录,“异步”是行业中非常的标准用法,而不是按时间顺序 - 我的意见判断调用是你的分析不正确。术语同步和异步的技术含义与常见含义并不完全相同。

标签: javascript browser asynchronous


【解决方案1】:

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

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

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

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

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

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

带上一粒盐,不要吃得太多。

【讨论】:

  • 我相信他在谈论 UI 事件,如点击、键盘输入等。这些肯定是不可预测的。但我喜欢你的最后一句话! :)
【解决方案2】:

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

身体问题

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

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

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

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

标题问题

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

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

最后的想法

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

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

【讨论】:

    【解决方案3】:

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

    事件的处理和它们的回调调用是异步的,但不一定是回调本身。

    我也发现这是一个定义:

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

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

    【讨论】:

    • 同意,另一种说法是你的事件处理程序是同步运行的,也就是说,一旦一个事件处理程序被调用,它的堆栈必须在队列中的新事件被处理之前展开。还需要注意的是,如果您从事件处理程序综合触发事件,附加的处理程序也将被同步调用(跳跃队列)。
    【解决方案4】:

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

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

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

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

    我认为另一个困扰你的是

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

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

    • XHR 请求
    • 同一节点上的多个处理程序过去没有保证顺序,but they do now

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 桌面应用程序还依赖于在单个线程上运行的事件循环,该线程由操作系统管理。这个答案并不能让我相信 Resig 正确地使用了这个词。
      • 我明白我的解释不是很有说服力。我的观点是,异步是处理 UI 事件所必需的(使用事件循环或多线程,没关系),否则必须阻塞。对我来说,这就是那段的真正含义。
      • 我认为你是对的,这就是他的意思,我只是认为他使用了错误的术语。
      【解决方案6】:

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

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

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

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

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

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

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

      【讨论】:

        【解决方案7】:

        JavaScript 是异步的...它会继续处理代码,即使您调用的方法尚未返回...所以是的,这是正确的。这就是异步的定义:不同步...

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

        【讨论】:

        • JavaScript 是单线程的。浏览器实现线程来处理事件等,但 JavaScript 本身不是异步的。
        • true...抱歉的意思是这样写:可以使用异步...但是引用中关于事件触发顺序的定义/陈述是准确的/是异步的...
        • 这不是真的。 JavsScript 不会“处理代码,即使您调用的方法尚未返回”。事件循环中的每条消息都会运行到完成。单击此处获取有关 JavaScript Concurrency model and Event Loop 的 mozilla 文档。
        • JS 代码执行是同步的,除非你调用 async 方法并指示它们在 async 方法完成后执行 [sync] 代码块
        猜你喜欢
        • 1970-01-01
        • 2017-08-04
        • 1970-01-01
        • 2011-08-02
        • 1970-01-01
        • 1970-01-01
        • 2011-05-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多