From 14c338e28ed3cb19403eade13e68ad5ccba7cbfd Mon Sep 17 00:00:00 2001 From: llwwbb Date: Fri, 30 Nov 2018 22:34:50 +0800 Subject: [PATCH] Update blocking-vs-non-blocking.md Correct some errors --- .../docs/guides/blocking-vs-non-blocking.md | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/locale/zh-cn/docs/guides/blocking-vs-non-blocking.md b/locale/zh-cn/docs/guides/blocking-vs-non-blocking.md index ac476f4048108..652d3e243b053 100644 --- a/locale/zh-cn/docs/guides/blocking-vs-non-blocking.md +++ b/locale/zh-cn/docs/guides/blocking-vs-non-blocking.md @@ -5,30 +5,31 @@ layout: docs.hbs # 阻塞对比非阻塞一览 -本概论涵盖了在 Node.js 中 **阻塞** and **非阻塞** 的区别,同时也会牵涉到时间轮询和 libuv 方面,不需要先行了解这些方面的知识也可以继续阅读。我们假定读者对于 JavaScript 语言和 Node.js 的回调机制有一个基本的了解。 +本文介绍了在 Node.js 中 **阻塞** 和 **非阻塞** 调用的区别。本文涉及事件循环和 libuv ,但不必对其有事先了解。我们假定读者对于 JavaScript 语言和 Node.js 的回调机制有一个基本的了解。 -> "I/O" 指的是系统磁盘和由 [libuv](http://libuv.org/) 支持的网络之间的交互。 +> "I/O" 主要指由[libuv](http://libuv.org/)支持的,与系统磁盘和网络之间的交互。 ## 阻塞 -**阻塞** 是说 Node.js 中其它的 JavaScript 命令必须等到一个非 JavaScript 操作完成之后才可以执行。这是因为当 **阻塞** 发生时,事件机制无法继续运行JavaScript。 +**阻塞** 是指在 Node.js 程序中,其它 JavaScript 语句的执行,必须等待一个非 JavaScript 操作完成。这是因为当 **阻塞** 发生时,事件循环无法继续运行JavaScript。 -在 Node.js 中,JavaScript由于 CPU 密集操作而表现不佳。而不是等待非 JavaScript操作 (例如I/O)。这被称为 **阻塞**。在 Node.js 基本类库中,使用 libuv 的同步方法大多数都是 **阻塞** 的。原生方法也可能是 **阻塞** 的。 +在 Node.js 中,JavaScript 由于执行 CPU 密集型操作,而不是等待一个非 JavaScript 操作(例如I/O)而表现不佳,通常不被称为 **阻塞**。在 Node.js 标准库中使用 libuv 的同步方法是最常用的 **阻塞** 操作。原生模块中也有 **阻塞** 方法。 -所有在 Node.js 中提供的 I/O 方法也包括异步版本,它们都是 **非阻塞** 的,接受回调函数。一些方法同时也具备 **阻塞** 功能,它们的名字结尾都以 `Sync` 结尾。 +在 Node.js 标准库中的所有 I/O 方法都提供异步版本,**非阻塞**,并且接受回调函数。某些方法也有对应的 **阻塞** 版本,名字以 `Sync` 结尾。 ## 代码比较 -**阻塞** 方法执行起来是 **同步地**,但是 **非阻塞** 方法执行起来是 **异步地**。 -如果你使用文件系统模块读取一个文件,同步方法看上去如下: +**阻塞** 方法 **同步** 执行,**非阻塞** 方法 **异步** 执行。 + +使用文件系统模块做例子,这是一个 **同步** 文件读取: ```js const fs = require('fs'); -const data = fs.readFileSync('/file.md'); // blocks here until file is read +const data = fs.readFileSync('/file.md'); // 在这里阻塞直到文件被读取 ``` -这是一个与之功能等同的 **异步** 版本示例: +这是一个等同的 **异步** 示例: ```js const fs = require('fs'); @@ -37,18 +38,18 @@ fs.readFile('/file.md', (err, data) => { }); ``` -第一个示例看上去比第二个似乎简单些,但是有一个缺陷:第二行语句会 **阻塞** 其它 JavaScript 语句的执行直到整个文件全部读取完毕。注意在同步版本的代码中,任何异常都会抛出,会导致整个程序崩溃。在异步版本示例代码中,它由作者来决定是否抛出异常。 +第一个示例看上去比第二个简单些,但是有一个缺陷:第二行语句会 **阻塞** 其它 JavaScript 语句的执行直到整个文件全部读取完毕。注意在同步版本中,如果错误被抛出,它需要被捕获否则整个程序都会崩溃。在异步版本中,由作者来决定错误是否如上所示抛出。 -让我们扩展一点我们的同步代码: +让我们稍微扩展一下我们的例子: ```js const fs = require('fs'); -const data = fs.readFileSync('/file.md'); // blocks here until file is read +const data = fs.readFileSync('/file.md'); // 在这里阻塞直到文件被读取 console.log(data); -// moreWork(); will run after console.log +// moreWork(); 在console.log之后执行 ``` -这是一个类似的,但是功能上不等同的异步代码示例版本: +这是一个类似但不等同的异步示例: ```js const fs = require('fs'); @@ -56,24 +57,24 @@ fs.readFile('/file.md', (err, data) => { if (err) throw err; console.log(data); }); -// moreWork(); will run before console.log +// moreWork(); 在console.log之前执行 ``` -第一个示例代码中, `console.log` 将在 `moreWork()` 之前被调用。在第二个例子中, `fs.readFile()` 因为是 **非阻塞** 的,所以 JavaScript 会继续执行, `moreWork()` 将被首先调用。`moreWork()` 无需等待文件读完而先行执行完毕,这对于高效吞吐来说是一个绝佳的设计。 +在上述第一个例子中, `console.log` 将在 `moreWork()` 之前被调用。在第二个例子中, `fs.readFile()` 是 **非阻塞** 的,所以 JavaScript 执行可以继续, `moreWork()` 将被首先调用。在不等待文件读取完成的情况下运行 `moreWork()` 的能力是一个可以提高吞吐量的关键设计选择。 -## 并行和吞吐 +## 并发和吞吐量 -在 Node.js 中 JavaScript 的执行是单线程的,所以并行与事件轮询能力(即在完成其它任务之后处理 JavaScript 回调函数的能力)有关。任何一个企图以并行的方式运行的代码必须让事件轮询机制以非 JavaScript 操作来运行,像 I/O 操作。 +在 Node.js 中 JavaScript 的执行是单线程的,因此并发性是指事件循环在完成其他工作后执行 JavaScript 回调函数的能力。任何预期以并行方式运行的代码必须让事件循环继续运行,因为非 JavaScript 操作(像 I/O )正在发生。 -举个例子,让我们思考一个案例:案例中每个对服务器的请求消耗 50 毫秒完成,其中的 45 毫秒又是可以通过异步操作而完成的数据库操作。选择 **非阻塞** 操作可以释放那 45 毫秒用以处理其它的请求操作。这是在选择 **阻塞** 和 **非阻塞** 方法上的重大区别。 +例如,让我们思考这样一种情况:每个对 Web 服务器的请求需要 50 毫秒完成,而那 50 毫秒中的 45 毫秒是可以异步执行的数据库 I/O。选择 **非阻塞** 异步操作可以释放每个请求的 45 毫秒来处理其它请求。仅仅是选择使用 **非阻塞** 方法而不是 **阻塞** 方法,就是容量上的重大区别。 -Node.js 中的事件轮询机制和其它语言相比而言有区别,其它语言需要创建线程来处理并行任务。 +事件循环不同于许多其他语言的模型,其它语言创建额外线程来处理并发工作。 -## 把阻塞和非阻塞代码混在一起写的危险 +## 混合阻塞和非阻塞代码的危险 -在处理 I/O 问题时,有些东西必须避免。下面让我们看一个例子: +处理 I/O 时应该避免一些模式。我们来看一个例子: ```js const fs = require('fs'); @@ -84,7 +85,7 @@ fs.readFile('/file.md', (err, data) => { fs.unlinkSync('/file.md'); ``` -在以上的例子中, `fs.unlinkSync()` 极有可能在 `fs.readFile()` 之前执行,所以在真正准备开始读取文件前此文件就已经被删除了。一个更好的处理方法就是彻底让使它变得 **非阻塞化**,并且保证按照正确顺序执行: +在以上的例子中, `fs.unlinkSync()` 极有可能在 `fs.readFile()` 之前执行,它会在实际读取之前删除 `file.md` 。更好的写法是完全 **非阻塞** 并保证按正确顺序执行: ```js const fs = require('fs'); @@ -97,10 +98,10 @@ fs.readFile('/file.md', (readFileErr, data) => { }); ``` -以上代码在 `fs.readFile()` 用异步方式调用 `fs.unlink()`,这就保证了执行顺序的正确。 +以上代码在 `fs.readFile()` 的回调中对 `fs.unlink()` 进行了 **非阻塞** 调用,这保证了正确的操作顺序。 -## 其它资料 +## 其它资源 - [libuv](http://libuv.org/) -- [关于 Node.js](https://nodejs.org/en/about/) +- [关于 Node.js](https://nodejs.org/zh-cn/about/)