1

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

4

2 回答 2

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 和/或内核的盒子,则将负载分散到多个进程中。

于 2014-11-15T04:07:35.967 回答
0

你的问题是一个很大的问题,所以我只关注一个部分。

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

非阻塞是一件美丽的事情XD

最佳实践包括:

  • 将每个功能分解为最小的功能形式。
  • 保持回调异步,是一篇关于使用回调的优秀帖子
  • 避免堆叠操作,(如嵌套循环)
  • 使用 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();' 擅长将大型运营链分解为较小的运营链,使一切更易于管理。

于 2014-11-15T03:51:17.530 回答