【问题标题】:How does JavaScript's Single Threaded Model handle time consuming tasks?JavaScript 的单线程模型如何处理耗时的任务?
【发布时间】:2014-11-15 12:07:35
【问题描述】:

这个问题是关于 JavaScript 的单线程模型的。我知道javascript本质上是非阻塞的,因为它能够向异步事件队列添加回调。但是如果回调函数确实需要很长时间才能完成,那么 JavaScript 会不会因为它是单线程的而在这段时间内阻塞其他所有内容? nodejs如何处理这样的问题?而对于前端的开发者来说,这是一个无法回避的问题吗?我问这个问题是因为我读过它通常是保持功能任务尽可能小的好习惯。真的是因为javascript中的长任务实际上会阻塞其他任务吗?

【问题讨论】:

  • 这是相当广泛的;你的代码会做什么这么耗时?
  • “我知道 javascript 本质上是非阻塞的” - 不,它不是。这是一些 node.js 的 API 函数的设计特征。 JavaScript 本身在每个函数调用期间都会阻塞。
  • 它不会倾向于冻结浏览器,它确实冻结浏览器。每个 JavaScript 函数调用都会这样做。它们中的大多数都发生得太快以至于你无法注意到,所以在你做一些耗时的事情之前这不是问题。
  • 不,阻塞是 any 单线程环境的限制。答案很简单:Node 不是单线程的。
  • 此外,节点将耗时的任务卸载到底层操作系统,为涉及等待的操作提供异步功能,如网络和磁盘 IO。

标签: javascript node.js single-threaded


【解决方案1】:

但是如果回调函数确实需要很长时间才能完成,那么 JavaScript 会不会因为它是单线程的而在这段时间内阻塞其他所有内容?

是的。

nodejs如何处理这样的问题?

Node.js 什么都不处理。如何处理并发取决于您和您的应用程序。现在,Node.js 确实有一些工具可供您使用。首先要了解的是,Node.js 基本上是 V8(JavaScript 引擎),带有一个轻量级库,在 JavaScript 和原生代码之间进行了拆分。虽然您的 JavaScript 代码本质上是单线程的,但本机代码可以并且确实会创建线程来处理您的工作。

例如,当您要求 Node.js 从磁盘加载文件时,您的请求将被传递到使用线程池的本机代码,并且您的数据是从磁盘加载的。发出请求后,您的 JavaScript 代码将继续运行。这就是 Node.js 上下文中“非阻塞”的含义。加载磁盘上的文件后,本机代码会将其传递给 Node.js JavaScript 库,然后使用适当的参数执行您的回调。您的代码在后台工作进行时继续运行,但是当您的回调处理该数据时,其他 JavaScript 代码确实被阻止运行。

这种架构让您无需实际编写任何多线程代码即可充分利用多线程代码的优势,从而使您的应用程序简单明了。

我之所以问这个问题,是因为我已经读到,将功能任务保持在尽可能小的范围内通常是一种很好的做法。真的是因为javascript中的长任务实际上会阻塞其他任务吗?

我的理念始终是按需使用。确实,如果一个请求进入您的应用程序,并且您有大量 JavaScript 处理阻塞的数据,则在此期间不会处理其他请求。但请记住,如果您正在执行此类工作,那么无论如何您都可能会受到 CPU 的限制,并且双倍的工作会导致两个请求都花费更长的时间。

实际上,大多数 Web 应用程序都受 IO 限制。他们对数据库中的数据进行洗牌,重新格式化,然后通过网络发送出去。与应用程序只是等待上游数据源回复的时间相比,它们处理数据的部分实际上并没有那么耗时。正是在这些应用程序中,Node.js 才真正大放异彩。

最后,请记住,您始终可以生成子进程以更好地分配负载。如果您的应用程序是一种罕见的应用程序,您 99% 的工作负载是在 CPU 密集型 JavaScript 中完成的,并且您有一个包含许多 CPU 和/或内核的盒子,请将负载分散到多个进程中。

【讨论】:

    【解决方案2】:

    您的问题非常大,所以我只关注其中的一部分。

    如果回调函数确实需要很长时间才能完成,那么 JavaScript 会不会因为它是单线程的而在这段时间内阻塞其他所有内容? (...) 真的是因为 javascript 中的长任务实际上会阻塞其他任务吗?

    无阻塞是一件美好的事情XD

    最佳实践包括:

    • 将每个函数分解为其最小函数形式。
    • 保持回调异步,THIS 是一篇关于回调使用的优秀帖子
    • 避免堆叠操作,(如嵌套循环)
    • 使用 setTimeout() 阻止潜在的阻塞代码
    • 还有很多其他方面,Node.JS 是无阻塞的黄金标准,因此值得一看。

    --

    --

    setTimeout() 是无阻塞代码中最重要的函数之一

    假设你做了一个如下所示的时钟函数:

    function setTime() {
        var date=new Date();
        time = date.getTime()
        document.getElementById('id').innerHTML = time;
    
    }
    while(true){setTime();}
    

    这很成问题,因为这段代码会愉快地循环自己直到时间结束。永远不会调用其他函数。您想停止操作,以便其他事情可以运行。

    function startTime() {
        var date=new Date();
        time = date.getTime()
        document.getElementById('id').innerHTML = time;
        setTimeout(startTime(),1000);
    }
    

    'setTimeout();'制动循环并每 1-ish 秒执行一次。无限循环是一个极端的例子。重点是'setTimeout();'擅长将大型运营链分解为较小的运营链,使一切更易于管理。

    【讨论】:

      猜你喜欢
      • 2011-10-01
      • 2015-01-10
      • 2012-12-05
      • 1970-01-01
      • 2020-04-17
      • 2020-06-16
      • 2014-07-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多