【问题标题】:Javascript sync and async processes priorityJavascript 同步和异步进程优先级
【发布时间】:2017-09-05 06:39:17
【问题描述】:

尽管是单线程的,但我正在研究 javascript 的异步行为,我在评论指出此代码:

request(..., function (error, response, body)  
    console.log('foo);  
});  
    callAComputationallyIntensiveSynchronousFunctionThatTakesSixHoursToExecute();  
console.log('bar');  

'bar' 仍然会出现在 'foo' 之前,因为 Javascript 总是首先完成当前正在执行的函数。事件永远不会中断函数。

我知道同步函数执行的优先级高于事件,但我不明白为什么 'bar' 会在 'foo' 之前打印。根据我的阅读,应该进行异步调用,然后在响应准备好之前填充死时间,它会继续处理其他代码行直到准备好,然后它应该执行响应的回调函数然后返回处理代码等等。

然而,上面的例子表明,即使响应在同步函数完成执行之前很久就准备好了,它仍然会继续执行下一行代码。这是为什么呢?

【问题讨论】:

    标签: javascript asynchronous process


    【解决方案1】:

    在 JavaScript 中,一切都是函数。同步函数和异步函数之间没有区别。 唯一的区别是调用这些函数的方式。所以“sync”/“async”对于程序员来说是一个抽象的概念,让交流更容易。

    JavaScript 的实际工作原理:

    JavaScript 有一个等待执行的“函数”队列。每次您创建一个新的“异步函数”时,都会将其添加到此队列中。例如,当您执行setTimeout()、ajax 调用或仅仅是浏览器触发的“onClick”之类的 DOM 事件时,就会发生这种情况。

    如果一个特定的函数在 JS 中执行,它永远不会被中断——它会一直运行到它完成(返回)。之后,运行时(浏览器)查看队列,决定接下来应该执行哪个函数,然后调用它——等待它完成。

    在上面的示例中,浏览器当前正在执行将打印“bar”的函数。此执行在完成之前不能被中断,因此首先打印“bar”。但是,在执行期间,会创建一个新的异步函数并将其推送到执行队列。只有在 "bar" 被打印后,运行时才会在队列中查找 "foo" 函数并执行它。

    这样做的负面影响是长时间运行的任务。在执行这样的功能时,浏览器无法执行任何其他操作。甚至没有渲染/更新页面。因此,如果您有一段代码运行 10 秒,那么用户在函数完成之前无法与网站交互。原因是所有用户事件,如鼠标移动、点击和滚动事件都在排队,直到线程完成长时间运行的任务才能处理。

    使用 JavaScript 进行多线程

    在 HTML5 中,JavaScript 现在有机会使用 web workers 来使用多个线程。但这是一个完全不同的话题,超出了这个问题的范围。请记住,理论上是可行的。

    【讨论】:

    • 感谢您的回答,但我认为您可能误解了代码中的某些内容,但我不确定。 console.log('bar') 跟在computationalHeavyFunction 后面,并不是函数的效果。从你所说的,我了解到在完成“同步”功能后,它应该查看队列并看到请求正在等待执行,因为解析器没有到达 console.log('bar' ) 指令将其添加到队列中。此外,运行时如何决定接下来选择队列中的哪个函数?
    • 不完全。例如 ajax 调用 确实是异步的,它在自己的线程中运行。与此同时,浏览器继续执行原始脚本,最终将控件移至用户(和事件队列)。当ajax线程准备好后,执行JS回调,为浏览器保留“唯一”线程。
    • 在与一些同事讨论了这个答案之后,我想我现在完全了解它是如何工作的。脚本是它们的方式函数,它们首先被添加到队列中,然后它开始执行并将新的“异步”函数添加到队列中,同时继续执行剩余的函数。只有在机器完成执行当前队列函数(在这种情况下是脚本本身)之后,它才会查看队列并决定接下来执行哪个函数(可能是请求回调或其他脚本),而不是像我想象的那样在每个函数调用之后。
    • @Andu 是的,它遵循计算量大的功能。所以它只在 6 小时后打印。在这 6 个小时内,“foo”函数在队列中等待,并在“bar”被打印后启动。
    • @Teemu 正确,HTTP 请求是浏览器实际在后台并行执行的少数事情之一。但这是浏览器的细节——从 JavaScript 的角度来看,Ajax 调用的响应是通过在主 UI 线程上运行的正常回调函数接收的——因此如果当前正在进行 6 小时的作业,则不会执行它。跨度>
    猜你喜欢
    • 2013-06-30
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 1970-01-01
    • 2018-06-29
    • 2021-06-15
    • 2011-06-25
    • 1970-01-01
    相关资源
    最近更新 更多