关于javascript:Nodejs-Web开发第二章2

35次阅读

共计 20179 个字符,预计需要花费 51 分钟才能阅读完成。

电子书举荐

Digital Forensics with Kali Linux, 2nd Edition

Debugging CSS

Practical Entity Framework Core 6: Database Access for Enterprise Applications, 2nd Edition

Hacking: Learn How to Hack Like a Pro

Hands on Hacking

JavaScript Cookbook: Programming the Web, 3rd Edition

Interactive Data Visualization with Python

Introduction to Deep Learning

Lean Python: Learn Just Enough Python to Build Useful Tools

Learn C++ Quickly

从 nodejs.org 下载安装 Node.js 安装包

Node.js 官网 https://nodejs.org/en/ 网站提供了 Windows、macOS、Linux 和 Solaris 等零碎的二进制安装文件。咱们只需进入 Node.js 官网,点击装置按钮,而后运行安装程序就可装置 Node.js。对于带有包治理 的零碎,如咱们下面探讨的,最好应用包管理系统装置。这是因为你会发现应用包管理系统装置形式更加容易更新 Node.js 的最新版本。然而种装置形式并不适宜所有开发者,起因如下:

  • 有些人更喜爱装置二进制文件,而不是应用包管理器装置软件。
  • 他们抉择的零碎没有包管理系统。
  • 他们的包管理系统中的 Node.js 实现已过期。

关上 Node.js 网站,您就会看到如下屏幕截图所示的内容。该页面尽最大致力确定您的操作系统并提 供适当的版本下载。如果您须要其余版本,请单击题目中的下载链接以获取所有可下载的版本:

macOS 零碎的 Node.js 安装包是一个 PKG 文件。不论是 MacOS 零碎还是 Windows 零碎,装置过程都和装置惯例软件过程是一样的。
在装置 Node.js 程序过程中,命令行工具例如 node 和 npm 也会同时被装置。因而装置实现后,你能够间接应用 npm 和 npx 命令运行 node.js 程序。Windows 零碎还提供了一个预配置的 Windows 命令 shell 版本,能够很好地与 Node.js 配合应用。
正如您你刚刚理解到的,咱们大多数人都喜爱应用 Node.js 安装包装置 Node.js。然而,有时咱们必须应用源代码装置 Node.js。

在相似 POSIX 的零碎上应用源代码装置

应用 Node.js 安装包装置 Node.js 发行版是首选的装置办法。然而应用源代码装置 Node.js 具备以下几个长处:

  • 你能够依据须要优化编译器设置。
  • 你能够穿插编译,比方编译嵌入式 ARM 零碎。
  • 你能够依据须要装置多个 Node.js 版本以进行测试。
  • 你可能正在解决 Node.js。

当初您曾经理解为什么要应用源代码装置 Node.js,让咱们通过一些构建脚本来入手安 装 Node.js。装置过程遵配置、制作和安装程序等惯例装置过程,您可能曾经应用其余开源软件包执行了该过程。如果没有,请不要放心,我将领导你实现整个过程。
官网装置阐明文件见 README.md 文件,网址为 https://github.com/nodejs/nod…。

装置前提条件

在应用源代码装置 Node.js 前,咱们须要装置三个工具:C 编译器、Python 和 OpenSSL 库。Node.js 编译过程查看会检测这个三款个工具是否 存在。如果 C 编译器或 Python 不存在,则编译将失败。请用以下命令将查看 C 编译器和 Python 是否存已装置:

$ cc --version
Apple LLVM version 10.0.0 (clang-1000.11.45.5)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xct oolchain/usr/bin 
$ python
Python 2.7.16 (default, Oct 16 2019, 00:35:27)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information. >>>

具体的装置办法取决于您的操作系统。
Node.js 构建工具正在更新以反对 Python 3.x。Python2.x 正处于生命周期完结阶段,打算于 2019 年底完结保护,因而倡议你将 Python2.x 更新到 Python3.x。
在编译 Node.js 源代码之前,咱们必须装置正确的工具。在 macOS 上,有几个非凡的事项须要留神。

在 macOS 上装置开发者工具

开发工具(如 GCC)是 macOS 上的可选装置工具。侥幸的是,这些很容易取得。
你能够首先装置 Xcode,Xcode 能够通过 Mac 利用商店收费下载。只需搜寻 Xcode 并单击“获取”按钮。安 装 Xcode 后,关上终端窗口并输出以下内容:

$ xcode-select --install

这就装置了 Xcode 命令行工具

无关更多信息,请拜访:http://osxdaily.com/2014/02/1…。
当初咱们曾经装置了须要的工具,能够持续编译 Node.js 源代码。

在所有类 POSIX 的零碎应用源代码装置 Node.js

应用源代码编译装置 Node.js 的过程如下:

  1. 源代码下载地址 http://nodejs.org/download。
  2. 应用./Configure 配置用于构建的源代码。
  3. 运行 make,而后运行 make install

源代码绑定包能够通过浏览器下载,也能够按以下形式下载替换你喜爱的版本:

$ mkdir src
$ cd src
$ wget https://nodejs.org/download/release/v14.0.0/node-v14.0.0.tar.gz 
$ tar xvfz node-v14.0.0.tar.gz
$ cd node-v14.0.0

当初咱们通过配置源代码来构建 Node.js。与许多其余开源包一样,有一系列选项可用于自定义构建 Node.js:

$ ./configure --help

要将 Node.js 装置到你的主目录,请运行以下命令:

$ ./configure --prefix=$HOME/node/14.0.0 ..output from configure

如果要同时装置多个版本的 Node.js,请应用以下命令将将版本号配置到 PATH 中。这样,每个版本将被装置 到一个独自的目录中。而后,通过更改响应的 PATH 变量就能够很简略地在 Node.js 的版本之间切换:

#On bash shell:
$ export PATH=${HOME}/node/VERSION-NUMBER/bin:${PATH} # On csh
$ setenv PATH ${HOME}/node/VERSION-NUMBER/bin:${PATH}

装置多个 Node.js 版本的一种更简略的办法是应用 nvm 脚本,这种装置形式咱们将在前面理解。
如果要将 Node.js 装置到系统目录中,只需省略 –prefix,Node.js 就会被默认装置到系统目录 /usr/ local 中。
期待一段时间,装置就会进行,并且可能曾经胜利地配置了源代码树,以便将 Node.js 装置到你抉择的目录中。如果装置不胜利,则打印的谬误音讯将形容须要修复的内容。一旦满足配置脚本的要求,就能够进入下一 步。
在满足配置脚本的状况下,您能够编译软件:

$ make
.. a long log of compiler output is printed 
$ make install

如果要将 Node.js 装置到系统目录中,请应用以下代码执行最初一步:

$ echo 'export PATH=$HOME/node/14.0.0/bin:${PATH}' >>~/.bashrc 
$ . ~/.bashrc

或者,对于 csh 用户,应用以下语法导出生成的环境变量:

$ echo 'setenv PATH $HOME/node/14.0.0/bin:${PATH}' >>~/.cshrc 
$ source ~/.cshrc

装置构建时,下面的命令会创立一个目录构造,如下所示:

$ ls ~/node/14.0.0/
bin   include   lib   share $ ls ~/node/14.0.0/bin
node npm npx

当初,咱们曾经理解了如何在类 UNIX 零碎上应用源代码装置 Node.js,咱们能够在 Windows 上执行同样的 操作。

在 Window 上应用源代码装置 Node.js

后面援用的 BUILDING.md 文档蕴含了装置阐明。您能够应用 Visual Studio 的构建工具或残缺的 Visual Studio 2017 或 2019 产品装置 Node.js:

  • Visual Studio 2019: https://www.visualstudio.com/…
  • 构建工具: https://visualstudio.microsof…

须要另外三个工具:

  • Windows 版 Git:http://git-scm.com/download/win
  • Python:https://www.python.org/
  • OpenSSL:https://www.openssl.org/source/ 和 https://wiki. openssl.org/index.php/Binaries
  • 用于 OpenSSL 的 Netwide 汇编器(NASM):https://www.nasm.us/

而后,运行内置的.\vcbuild 脚本执行构建。
咱们曾经学习了如何装置一个 Node.js 实例,当初让咱们来理解一下如何装置多个实例。

应用 nvm 装置多个版本 Node.js

咱们通常不会装置多个版本的 Node.js,因为这样做会减少零碎的复杂性。然而,如果您正在对 Node.js 进行模仿黑客攻击演练,或者针对不同的 Node.js 版本测试你的利用,那么你可能须要装置多个 Node.js 实例。装置办法只是对后面装置办法进行简略的批改。
在后面探讨从源代码构建 Node.js 时,咱们留神到能够在独自的目录中装置多个 Node.js 实例。如果您须要 定制的 Node.js 构建,那么只须要应用源代码装置就能够了。但大多数人都比拟喜爱应用 Node.js 安装包安 装 Node.js 并且也能够装置在独自的目录中。
在 Node.js 版本之间切换只须要将装置 Node.js 的目录增加到 PATH 变量中,POSIX 零碎应用如下代码:

$ export PATH=/usr/local/node/VERSION-NUMBER/bin:${PATH}

然而工夫一长,保护会变得越来越艰难。因为咱们须要对不同版本的 Node.js 进行设置,包含 npm 和咱们 要是用的第三发模块。此外,频繁更改 PATH 变量也是十分麻烦的,因而有开发者创立了几个版本治理 器,以简化对多个 Node.js/npm 版本的治理,并提供了更改 PATH 变量的智能命令:

  • Node 版本管理器:https://github.com/tj/n
  • Node 版本管理器:https://github.com/creationix…

这两个版本管理器都用于保护 Node.js 的多个版本,并且可能让你非常简单在不同的 Node.js 版本之间切 换。装置阐明可在这个工具的官方网站上取得。例如,应用 nvm,你能够运行以下命令:

$ nvm ls
...
v6.4.0
...
v6.11.2
v8.9.3
v10.15.2
...
v12.13.1
...
v14.0.0
-> system
default -> 12.9.1 (-> v12.9.1)
node -> stable (-> v12.13.1) (default) stable -> 12.13 (-> v12.13.1) (default) 
$ nvm use 10
Now using node v10.15.2 (npm v6.4.1)
$ node --version
v10.15.2
$ nvm use 4.9
Now using node v4.9.1 (npm v2.15.11)
$ node --version
v4.9.1
$ nvm install 14
Downloading and installing node v14.0.0... Downloading 
https://nodejs.org/dist/v14.0.0/node-v14.0.0-darwin-x64.tar.xz... ############... 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v14.0.0 (npm v6.14.4)
$ node --version
v14.0.0
$ which node
/Users/david/.nvm/versions/node/v14.0.0/bin/node
$ /usr/local/bin/node --version
v13.13.0
$ /opt/local/bin/node --version
v13.13.0

在本例中,咱们首先列出了已装置的版本。而后,咱们演示了如何切换,并测验切换后的版本。咱们还装置了 nvm 的新版本。最初,咱们展现了 nvm 装置 Node.js 软件包的目录,以及应用 MacPorts 或 Homebrew 装置的 Node.js 版本。
这表明您能够在系统目录中装置 Node.js,由 nvm 治理多个公有的 Node.js 版本,并依据须要在它们之间切换。新的 Node.js 版本公布后,即便您的操作系统的官网软件包管理器尚未更新其软件包,也能够应用 nvm 轻松装置。

在 Windows 上装置 nvm

可怜的是,nvm 不反对 Windows。侥幸的是,有几个 Windows 零碎的 nvm 克隆版本:

  • 实用于 Windows 的 Node.js 版本治理实用程序:https://github.com/coreybutle…
  • 实用于 Windows 的 Natural Node.js 和 npm 版本管理器:https://github.com/marcelkleh…

另一种办法是应用 WSL。因为在 WSL 中,Windows 10 自带了 Linux 子系统,所以能够应用 nvm 自身。然而,让咱们持续关注如何在 Windows 中装置 nvm。
本书中的许多示例都应用 nvm-windows 应用程序进行了测试。尽管有轻微的执行差别,但其执行与 Linux 和 macOS 上的 nvm 基本相同。最大的变动是 nvm use 和 nvm install 命令中的版本号说明符。
应用 nvm for Linux 和 macOS,您能够输出一个简略的版本号,例如 nvm use 8,它将主动替换命 名 Node.js 的最新版本。对于 nvm-Windows,nuv use 8 与 nvm use 8.0.0 的作用是雷同的。换句话说,对 于 nvm-windows,您必须应用确切的版本号。侥幸的是,应用 nvm list available 命令能够轻松取得受反对版本的列表。
应用诸如 nvm 之类的工具简化了针对多个 Node.js 版本测试 Node.js 应用程序的过程。
当初咱们能够装置 Node.js 了,咱们须要确保咱们正在装置任何咱们想要应用的 Node.js 模块。这须要在咱们的计算机上安装构建工具。

装置原生代码模块的要求

尽管在本书中咱们不会探讨原生代码模块开发,但咱们的确须要确保它们能够构建。NPM 存储库中的一 些模块是原生代码,它们必须用 C 或 C ++ 编译器编译,以构建相应的.No.Frm 文件(.No.Exchange 用于二 进制原生代码模块)。
该模块通常是其余库的包装器。例如,libxslt 和 libxmljs 模块是同名 C /C++ 库的包装器。该模块蕴含 C /C++ 源代码,装置后会主动运行应用 node-gyp 编译的脚本。
node-gyp 工具是一个用 node.js 编写的跨平台命令行工具,用于编译 node.js 的原生附加模块。咱们屡次 提到的原生代码模块就是用这个工具编译的,用于与 Node.js 一起应用。
通过运行以下命令,您能够很容易地看到这一点:

$ mkdir temp
$ cd temp
$ npm install libxmljs libxslt

这是在长期目录中实现的,因而您能够在当前删除它。如果您的零碎没有装置编译原生代码模块的工 具,您将看到谬误音讯。否则,您将在输入中看到一个 node-gyp 执行,前面是许多显然与编译 C /C++ 文 件相干的文本行。
node-gyp 工具的先决条件与从源代码编译 node.js 的先决条件相似,即 C /C++ 编译器、Python 环境和其余构建工具,如 Git。对于 Unix、macOS 和 Linux 零碎,这些都很容易取得。对于 Windows,您应该装置以下组件:

  • Visual Studio 构建工具: https://www.visualstudio.com/…
  • Windows 版 Git: http://git-scm.com/download/win
  • Windows 版 Python: https://www.python.org/

通常,您不须要装置 node-gyp,这是因为它作为 npm 的一部分主动装置的。这样,npm 就能够主动构建原生代码模块。
其 GitHub 存储库蕴含文档,请拜访:https://github.com/nodejs/nod…。
浏览其存储库中的 node-gyp 文档将使您更分明地理解后面探讨的编译先决条件以及开发原生代码模块。这是一个非显式依赖关系的示例。最好明确申明软件包所依赖的所有内容。在 Node.js 中,依赖项在 package.json 中申明,以便包管理器(npm 或 Thread)能够下载和设置所有内容。但这些编译器工具 是由操作系统包管理系统设置的,不受 npm 或 yarn 的管制。因而,咱们不能显式地申明这些依赖项。
咱们刚刚理解到 Node.js 不仅反对 JavaScript 编写的模块,还反对其余编程语言编写的模块。咱们还学习了如何装置此类模块。接下来,咱们将理解 Node.js 的版本号。

抉择要应用的 Node.js 版本和版本策略

在上一节中,咱们只是看到了太多不同的 Node.js 版本号,您可能会对应用哪个版本感到困惑。本书应用的 Node.js 版本为 14.x,咱们将介绍的所有内容都与 Node.js 10.x 和任何后续版本兼容。
从 Node.js 4.x 开始,Node.js 团队采纳了双轨办法。偶数版本(4.x、6.x、8.x 等等)是他们所谓的长期支 持(LTS),而奇数版本(5.x、7.x、9.x 等等)是以后新个性开发版本。尽管开发分支保持稳定,但 LTS 版本定位为供生产应用,并将在几年内失去更新。
在撰写本文时,Node.js 12.x 是以后的 LTS 版本;Node.js 14.x 曾经公布,最终将更新为 LTS 版本。
除了通常的性能改良和 bug 修复之外,各个新的 Node.js 版本的一个次要影响是引入了最新的 V8 JavaScript 引擎版本。反过来,这意味着在 V8 团队在保护 V8 引擎时会一直引入更多的 ES2015/2016/2017 功 能。Node.js 8.x 新增了 async/await 函数,Node.js 10.x 反对规范的 ES6 模块格局,Node.js 14.x 将齐全支 持 ES6 模块格局。
咱们要思考新的 Node.js 版本是否会毁坏您的代码。随着 V8 一直被退出 ECMAScript 新个性,并 且 Node.js 团队有时会对 Node.js API 进行破坏性的更改,新的语言个性总是被增加。如果您的代码曾经在 某个 Node.js 版本上进行了测试,那么它是否能够在晚期版本上运行?Node.js 的更改会突破咱们的一些假 设吗?
npm 的作用确保咱们的包在正确的 Node.js 版本上执行。这意味着咱们能够在 package.json 文件中为包指定兼容的 Node.js 版本(咱们将在第 3 章摸索 Node.js 模块中进行探讨)。
咱们能够向 package.json 增加一个版本条件,如下所示:

engines: {"node": ">=8.x"}

该代码要求给定的包与 Node.js 8.x 或更高版本兼容。
当然,您的开发环境能够装置多个 Node.js 版本。您须要申明软件反对的版本,以及您心愿评估的任何更 高版本。
咱们刚刚理解了 Node.js 社区如何治理发行版和版本号。咱们的下一步是探讨要应用的编辑器。

为 Node.js 抉择编辑器和调试器

因为 Node.js 代码是 JavaScript,因而所有反对 JavaScript 的编辑器都能够抉择。不像其余一些语言那么复 杂,以至于带代码补全性能是 IDE 必须具备的,一个简略的编程编辑器齐全能够满足 Node.js 开发的需 求。
有两个编辑器值得一提,因为它们自身就是用 Node.js 编写的:Atom 和 Microsoft Visual Studio Code。Atom(https://atom.io/)) 将本人形容为 21 世纪的可高度自定义的编辑器。它能够通过应用 Atom API 编 写 Node.js 模块进行扩大,并且配置文件很容易编辑。换句话说,它能够通过与许多其余编辑器一样的方 式进行目定斗,也就是说,您能够编写一个软件模块来减少编辑器的性能。Electron 框架是为了构 建 Atom 而创造的,它是应用 Node.js 构建桌面应用程序的一种非常简单的办法。
Microsoft Visual Studio Code(https://code.visualstudio.com/) 也是一个可高度自定义编辑器,并且也 是开源的,并应用 Electron 开发的。然而,它不是一个空洞的“我也是”编辑器,在走 Atom 的路同时 不,Visual Studio 代码自身就是一个牢靠的程序员编辑器,并且也有很多乏味的性能。
对于调试器,有几个乏味的抉择。从 Node.js 6.3 开始,inspector 协定使应用 Google Chrome 调试器成为 可能。Visual Studio Code 有一个内置调试器,也应用 inspector 协定。
无关调试选项和工具的残缺列表,请参阅 https://nodejs. org/en/docs/guides/debugging-getting-started/。
与编辑器相干的另一项工作是增加扩大以进步编程体验。大多数面向程序员的编辑器容许您扩大性能并 帮助编写代码。一个简略的例子是 JavaScript、CSS、HTML 等的语法着色性能。代码补全扩大是编辑器帮 助您编写代码性能。一些扩大扫描用于常见谬误的语法错误代码;这些扩大通常应用 lint 这个词示意。一 些扩大有助于运行单元测试框架。因为的抉择的编辑器切实太多,咱们不能提供具体的倡议。
对于一些人来说,编程编辑器的抉择是一个庄重的问题,因而咱们审慎地建议您应用您喜爱的编辑器,只有它有助于您编写 JavaScript 代码即可。接下来,咱们将学习 Node.js 命令和一些对于运行 Node.js 脚本 的常识。

运行和测试命令

当初您曾经装置了 Node.js,咱们想做两件事来验证装置是否胜利,并相熟 Node.js 命令行工具和使 用 Node.js 运行简略脚本。咱们还将再次探讨异步函数,并看一个简略的 HTTP 服务器示例。咱们将使 用 npm 和 npx 命令行工具耒完结本章。

应用 Node.js 的命令行工具

Node.js 有两个根底装置命令:node 和 npm。咱们曾经看到正在运行 node,次要用于运行命令行脚本或 服务器过程。另一个是 npm,它是 Node.js 的包管理器。
验证 Node.js 是否装置的最简略的无效办法是获取 Node.js 帮忙。输出以下命令:

$ node --help
Usage: node [options] [-e script | script.js | -] [arguments]
node inspect script.js [arguments]
Options:
-v, --version print Node.js version
-  e, --eval script evaluate script
-  p, --print evaluate script and print result
-  c, --check syntax check script without executing
-  i, --interactive always enter the REPL even if stdin
does not appear to be a terminal
-  r, --require module to preload (option can be repeated)
-  script read from stdin (default; interactive mode if a tty)
... many more options
Environment variables:
NODE_DEBUG ','-separated list of core modules that should print debug information 
NODE_DEBUG_NATIVE ','-separated list of C++ core debug categories that should print debug output
NODE_DISABLE_COLORS set to 1 to disable colors in the REPL
NODE_EXTRA_CA_CERTS path to additional CA certificates file
NODE_NO_WARNINGS set to 1 to silence process warnings
NODE_OPTIONS set CLI options in the environment via a space-separated list
NODE_PATH ':'-separated list of directories prefixed to the module search path
... many more environment variables

咱们失去了很多的输入内容,这内容不需具体理解。关键在于 node–help 提供了很多有用的信息。
请留神,Node.js 和 V8 都有选项(在后面的命令行中未显示)。记住 Node.js 是构建在 V8 之上的;它有本人的选项体系,次要是对于字节码编译或垃圾收集和堆算法的细节。输出 node –v8-options 就能够查看 这些选项的残缺列表。
咱们能够在命令行上指定选项、单个脚本文件以及该脚本的参数列表。咱们将在下一节中进一步探讨脚 本参数并应用 Node.js 运行一个简略的脚本。
运行没有参数的 Node.js 能够让咱们应用 JavaScript shell 间接编写运行 JavaScript 代码:

$ node
> console.log('Hello, world!'); Hello, world! undefined

咱们在 Node.js 脚本中编写的所有代码都能够在这里编写。命令解释器提供了良好的面向终端的用户体 验,对于以交互方式解决代码十分有用。

应用 Node.js 运行简略脚本

当初,让咱们看看如何应用 Node.js 运行脚本。这很简略;让咱们从后面显示的帮忙信息开始。命令行模式只是一个脚本文件名和一些脚本参数,任何应用其余语言编写脚本的人都应该相熟这些参数。
我你能够应用任意解决的文本编辑器来创立和编辑 Node.js 脚步,
如 VI/VIM、Emacs、Notepad++、Atom、Visual StudioCode、Jedit、BB Edit、TextMate 或 Komodo 等等。如果是一个面向程序员的编辑器,即便只是语法着色,也是很有帮忙的。
对于本书中的源代码文件,放在哪里并不重要。然而,为了整洁起见,您能够在计算机的主目录中创立 一个名为 node-web-dev 的目录,并在该目录中给每个章节创立一个目录(例如,chap02 和 chap03)。首先,创立一个名为 ls.js 的文件,其中蕴含以下内容:

const fs = require('fs').promises;
async function listFiles() {
   try {const files = await fs.readdir('.'); 
     for (const file of files) {console.log(file);
      }
     } catch (err) {console.error(err);
     }
   }
   listFiles();

接下来,在命令框中输出以下命令来运行文件。(译者注:如果 js 文件不在以后命令框所在目录的话,你须要先 将命令框定位到相应目录下)

$ node ls.js ls.js

这是对 unix ls 命令的一个非常简单的模拟(如同你不能从名称中看出!)。readdir 函数与用于列出目录 中文件的 Unix readdir 零碎调用命令十分类似。在 Unix/Linux 零碎上,咱们能够运行以下命令以理解更多 信息:

$ man 3 readdir

当然,man 命令能够让你浏览手册页面和第 3 部介绍的 C 库。
在函数体内,咱们读取目录并打印其内容。应用 require.(‘fs’).promises 为咱们提供了返回承诺的 fs 模块(文件系统函数)的版本;因而,fs 模块在异步函数中运行良好。同样,ES2015 for..of 循环结构容许咱们 以一种在异步函数中运行良好的形式循环数组中的元素。
默认状况下,fs 模块函数应用最后为 Node.js 创立的回调范例。因而,大多数 Node.js 模块都应用回调范例。在异 步函数中,如果函数返回承诺,则更不便,这样就能够应用 await 关键字。util 模块提供了一个函 数 util.promisify,它为新式的面向回调的函数生成一个包装函数,因而它返回一个承诺。
这个脚本被硬编码列出当前目录中的文件。真正的 ls 命令须要一个目录名,因而让咱们略微批改一下该脚 本。
命令行参数位于名为 process.argv 的全局数组中。因而,咱们能够批改 ls.js,将其复制为 ls2.js(如下所 示),以查看此数组的工作形式:

const fs = require('fs').promises;
async function listFiles() {
   try {
     var dir = '.';
     if (process.argv[2]) dir = process.argv[2]; 
     const files = await fs.readdir(dir); 
     for (let fn of files) {console.log(fn);
       }
        } catch (err) {console.error(err);
    }
  }
  listFiles();

你能够按如下形式运行:

$ pwd 
/Users/David/chap02
$ node ls2 ..
chap01
chap02
$ node ls2
app.js
ls.js
ls2.js

咱们只是查看命令行参数是否存在,if(process.argv[2])。如果存在,则重写 dir 变 量,dir=process.argv[2]的值,而后将其用作 readdir 参数:

$ node ls2.js /nonexistent
{ Error: ENOENT: no such file or directory, scandir '/nonexistent' 
errno: -2,
code: 'ENOENT',
syscall: 'scandir',
path: '/nonexistent' }

如果给定的目录门路不存在,将抛出一个谬误,并应用 catch 语句打印。
# 编写内联异步箭头函数
有一种不同的形式来写这些例子,有些人感觉更简洁。这些示例是用惯例函数编写的,带有 function 要害 字申明,但后面有 async 关键字。ES2015 新增了一个个性,即箭头函数,让咱们略微简化了代码。
联合 async 关键字,async 箭头函数如下所示:

async () => {// function body}

你能够在任何中央应用箭头函数。例如,该函数能够指定给变量,也能够作为回调传递给另一个函数。当与 async 关键字一起应用时,箭头函数体具备异步函数的所有行为。
对于这些示例,能够应用异步箭头函数以立刻执行:

(async () => {// function body})()

最初一个括号将使内联函数立刻被调用。
而后,因为异步函数返回一个承诺,所以有必要增加一个.catch 块来捕捉谬误。综上所述,更改后的示例
如下所示:

const fs = require('fs');
(async () => {
  var dir = '.';
  if (process.argv[2]) dir = process.argv[2]; 
  const files = await fs.readdir(dir);
  for (let fn of files) {console.log(fn);
  }
})().catch(err => { console.error(err); });

更改前后的代码哪一种更可取,取决于集体爱好。然而,您会发现这两种函数编写形式都在应用,因而 有必要理解把握。
在脚本的顶部调用异步函数时,有必要捕捉并报告所有谬误。未能捕捉和报告谬误可能导致难以确定的 神秘问题。对于本例的原始版本,谬误是通过 try/catch 块显式捕捉的。在这个版本中,咱们应用.catch 块 捕捉谬误。
在异步函数之前,咱们应用了 Promise 对象,在此之前,咱们应用回调范式。Node.js 中依然应用这三种 范式,这意味着您须要理解每一种范式。

转换为异步函数和 Promise

在上一节中,咱们探讨了 util.promisify 及其如向将面向回调的函数转换为返回承诺的函数。后者能够很好 地解决异步函数,因而,函数最好返回一个承诺。
更精确地说,util.promisify 将被赋予一个应用谬误优先回调范式的函数。此类函数的最初一个参数是回调 函数,它的第一个参数被解释为谬误批示符,因而称为 error-first-callback(谬误优先回 调)。util.promisify 返回的是另一个返回承诺的函数。
承诺的作用与谬误优先回调雷同。如果显示谬误,承诺将解析为回绝状态,而如果显示胜利,承诺将解 析为胜利状态。正如咱们在这些示例中看到的,在异步函数中能够很好地解决承诺。
Node.js 生态系统有大量应用谬误优先回调的函数。社区曾经开始了一个转换过程,其中函数将返回一个 承诺,并且可能还将首先进行谬误回调,以实现 API 兼容性。
Node.js 10 中的一个新个性就是这种转换的一个例子。fs 模块中有一个子模块,名为 fs.promises,具备相 同的 API,但生成 Promise 对象。咱们应用该 API 编写了后面的示例。
另一个抉择是第三方模块 fs-extra。此模块具备规范 fs 模块之外的扩大 API。一方面,如果没有提供回调函 数或调用回调函数,该模块的函数将返回一个承诺。此外,该模块还包合几个有用的函数。
在本书前面章节中,咱们将常常应用 fs-extra,因为咱们要应用到模块的其余额时函数。无关该模块的文档,请 访 https://www.npmjs.com/package…。
util 模块有另一个 util.callbackify 函数,该函数顾名思义将返回承诺的函数转换为应用回调函数的函数。
当初咱们曾经理解了如何运行一个简略的脚本,让咱们看看一个简略的 HTTP 服务器。

应用 Node.js 启动服务器

您要运行的许多脚本都是服务器过程;咱们前面会运行很多这样的脚本。为了让你可能熟练地装置验证 和应用 Node.js,因而咱们想要运行一个简略的 HTTP 服务器。让咱们借用 Node.js 主页上的简略的服务器 脚本 (http://nodejs.org)。
创立一个名为 app.js 的文件,其中蕴含以下内容:

const http = require('http');
http.createServer(function (req, res) { res.writeHead(200, 
  {'Content-Type': 'text/plain'}); res.end('Hello, World!\n');
}).listen(8124, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8124');

按如下形式运行:

$ node app.js
Server running at http://127.0.0.1:8124

这是能够应用 Node.js 构建的最简略的 web 服务器。如果您对它的工作原理感兴趣,请间接浏览 第 4 章“HTTP 服务器和客户端”、第 5 章“您的第一个 Express 应用程序”以及第 6 章“实现挪动优先范式”。然而 当初,只是在中输出 http://127.0.0.1:8124 查看 Hello,World!信息:

一个须要思考的问题是,当 ls.js 退出时,为什么这个脚本没有退出。在这两种状况下,脚本的执行都会达到文件的开端;Node.js 过程不会在 app.js 中退出,而会在 ls.js 中退出。
起因是存在流动事件侦听器。Node.js 总是启动一个事件循环,在 app.js 中,listen 函数创立一个实 现 HTTP 协定的事件(listener)。此侦听器事件将放弃 app.js 运行,直到您执行某些操作,例如在终端窗 口中按 Ctrl+C。在 ls.js 中,不会创立长时间运行的侦听器事件,因而当 ls.js 达到其脚本开端时,Node 过程将退出。
要应用 Node.js 执行更简单的工作,咱们必须应用第三方模块。这时候就该 npm 存储库出场了。

应用 npm,Node.js 包管理器

Node.js 是一个 JavaScript 解释器,有几个乏味的异步 I / O 库,它自身就是一个十分根底的零碎。Node.js 的 乏味之处之一是 Node.js 的第三方模块生态系统的快速增长。
该生态系统的外围是 npm 模块存储库。尽管 Node.js 模块能够作为源代码下载并手动组装以便用 于 Node.js 程序,但这样做很繁琐,而且很难实现可反复的构建过程。npm 给了咱们一个更简略的办法;npm 是 Node.js 的规范包管理器,它大大简化了下载和应用这些模块的难度。咱们将在下一章具体探讨 npm。
你们中眼光敏锐的人会留神到,我你曾经应用后面探讨的所有装置办法装置了 nmp。过来,npm 是独自 装置的,但当初它与 Node.js 是捆绑在一起的。
当初咱们曾经装置了 npm,让咱们来疾速理解一下。hexy 程序是一个用于打印十六进制文件转储的实用 程序。这是一款七十年代的程序,但它依然十分有用。它给咱们提供了疾速装置和试用的性能:

$ npm install -g hexy
/opt/local/bin/hexy -> 
/opt/local/lib/node_modules/hexy/bin/hexy_cmd.js+ hexy@0.2.10 added 1 package in 1.107s

增加 - g 标记使模块全局可用,而与命令 shell 的当前工作目录无关。当模块提供命令行界面时,全局装置最有用。当程序包提供命令行脚本时,npm 会设置该脚本。我已正确地全局装置 hex,供计算机的所有 用户应用。
依据 Node.js 的装置形式,它可能须要与 sudo 一起运行:

1 $ sudo npm install -g hexy

装置后,您能够通过以下形式运行新装置的程序:

$ hexy --width 12 ls.js
00000000: 636f 6e73 7420 6673 203d 2072 const.fs.=.r 
0000000c: 6571 7569 7265 2827 6673 2729 equire('fs') 
00000018: 3b0a 636f 6e73 7420 7574 696c ;.const.util 
00000024: 203d 2072 6571 7569 7265 2827 .=.require('00000030: 7574 696c 2729 3b0a 636f 6e73 util');.cons 
0000003c: 7420 6673 5f72 6561 6464 6972 t.fs_readdir 
00000048: 203d 2075 7469 6c2e 7072 6f6d .=.util.prom 
00000054: 6973 6966 7928 6673 2e72 6561 isify(fs.rea 
00000060: 6464 6972 293b 0a0a 2861 7379 ddir);..(asy 
0000006c: 6e63 2028 2920 3d3e 207b 0a20 nc.().=>.{.. 
00000078: 2063 6f6e 7374 2066 696c 6573 .const.files 
00000084: 203d 2061 7761 6974 2066 735f .=.await.fs_ 
00000090: 7265 6164 6469 7228 272e 2729 readdir('.') 
0000009c: 3b0a 2020 666f 7220 2866 6e20 ;...for.(fn. 
000000a8: 6f66 2066 696c 6573 2920 7b0a of.files).{. 
000000b4: 2020 2020 636f 6e73 6f6c 652e ....console. 
000000c0: 6c6f 6728 666e 293b 0a20 207d log(fn);...} 
000000cc: 0a7d 2928 292e 6361 7463 6828 .})().catch(
000000d8: 6572 7220 3d3e 207b 2063 6f6e err.=>.{.con 
000000e4: 736f 6c65 2e65 7272 6f72 2865 sole.error(e 
000000f0: 7272 293b 207d 293b rr);.});

hexy 命令作为全局命令装置,使其易于运行。
在下一章中,咱们将再次深入探讨 npm。hexy 实用程序既是一个 Node.js 库,也是一个用于打印这些老式 十六进制转储的脚本。
在开源世界中,满足不同开发者的需要是开源我的项目创立的不一刀衷。启动 Thread 我的项目的人员发 rnnpm 没有解决 的开发者的需要,因而创立了一个代替包管理器(Package Manager)的工具,即 yarn。他们声 称 yarn 与 npm 相比有许多劣势,次要是在性能方面。要理解无关 yarn 的更多信息,请转到 https://yarnpkg.com/。
对于本书中应用 npm 的每个示例,都有一个应用纱线的近似等效命令。
对于打包的 npm 命令行工具,有另一种更简略的办法来应用该工具。

应用 npx 执行 Node.js 打包的二进制文件

npm 存储库中的一些包是命令行工具,比方咱们后面看到的 hexy 程序。这些命令行工具在应用之前必须 先装置,这比拟麻烦。在装置 node.js 时,仔细的你肯定留神到了 npx 与 node 和 npm 命令是一起装置 的。npx 旨在通过打消首先要装置命令行软件包的须要,简化从 npm 存储库运行命令行工具的过程。
上一个示例能够这样运行:

$ npx hexy --width 12 ls.js

在这背地,npx 应用 npm 将包下载到缓存目录,除非包曾经装置到以后我的项目目录中。因为该包位于缓存目 录中,因而只需下载一次。
该工具有许多乏味的选项;要理解更多信息,请转到 www.npmjs.com/package/npx。
在本节中,咱们学习了很多 Node.js 自带的命令行工具,并运行了一个简略的脚本和 HTTP 服务器。接下 来,咱们将理解 JavaScript 语言的提高如何影响 Node.js 平台。

应用 ECMAScript 2015、2016、2017 及当前的版本晋升 Node.js

2015 年,ECMAScript 委员会公布了期待已久的 JavaScript 语言的重大更新。更新为 JavaScript 带来了许多新个性,如承诺、箭头函数和类对象。语言更新为改良奠定了根底,因为它将极大地提高咱们编写干 净、可了解的 JavaScript 代码的能力。
浏览器制造商正在增加这些急需的性能,这意味着 V8 引擎也在增加这些性能。从 4.x 版开始,这些个性就 退出进了 Node.js。
要理解 Node.js 中 ES2015/2016/2017/ 等的以后状态,请拜访 https://nodejs.org/en/docs/es6/。
默认状况下,Node.js 仅启用 V8 认为稳固的 ES2015、2016 和 2017 性能。能够应用命令行选项启用其余功 能。简直残缺的个性是通过 –es_staging 选项启用的。网站文档提供了更多信息。
node green 网站(http://node.green/) 有一个表,列出 Node.js 版本中一长串性能的状态。
ES2019 语言标准公布在 https://www.ecma-internationa…。TC-39 委员会在 GitHub 上发展工作,网址是:https://github. com/tc39。
ES2015(及更高版本)性能对 JavaScript 语言进行了重大改良。承诺(Promise)类的一个个性是对 Node.js 编程中常见习惯用法的根本性反思。在 ES2017 中,一对新关键字 async 和 await 简化了 在 Node.js 中编写异步代码的过程,这将激励 Node.js 社区进一步反思平台的常见的习惯用法。
新的 JavaScript 减少了很个性,但让咱们疾速浏览一下咱们将宽泛应用的这两个个性。
第一种是较轻的函数语法,称为简头函数:

fs.readFile('file.txt', 'utf8', (err, data) => {if (err) ...; // do something with the error 
  else ...;  // do something with the data
});

这不仅仅是用箭头代替 function 关键字的语法糖劣势。箭头函数更简洁,也更容易浏览。简洁的代价是改 变箭头函数中 this 的值。在一般函数中,this 在函数内具备一个惟一的值。在箭头函数中,this 的值与箭头 函数的作用域雷同。这意味着,当应用箭头函数时,咱们不用将 this 引入回调函数中,因为 this 在两个函
数中是一样的。
下一个个性是 Promise(承诺)类,用于提早和异步计算。提早代码执行以实现异步行为是 Node.js 的一 个要害范例,它须要两个习用约定:

  • 异步函数的最初一个参数是回调函数,在执行异步执行时调用回调函数。
  • 回调函数的第一个参数是谬误指示器。

这些约定尽管不便,但却导致了难以了解和保护的多层代码金字塔:

  doThis(arg1, arg2, (err, result1, result2) => {if (err)...;
      else {
        // do some work
        doThat(arg2, arg3, (err2, results) => {if (err2)...;
          else { 
            doSomethingElse(arg5, err => {if (err)..;
              else..;
            });
          }
        });
      }
    });

你不须要了解代码;这只是咱们应用回调时理论产生的状况的概要。依据特定工作须要的步骤,代码金 字塔可能会变得越来越深。承诺将让咱们解决代码金字塔问,进步代码的可靠性,因为错误处理更直 接,更容易捕捉所有谬误。
Promise 类的创立如下所示:

    function doThis(arg1, arg2) {return new Promise((resolve, reject) => { 
        // execute some asynchronous code
        if (errorIsDetected) return reject(errorObject); 
        // When the process is finished call this: 
        resolve(result1, result2);
      });
    }

调用方接管承诺对象,而不是传入回调函数。当正确应用时,后面的金字塔代码能够按如下形式重构:

doThis(arg1, arg2)
        .then((result) => {
          // This can receive only one value, hence to 
          // receive multiple values requires an object or array 
          return doThat(arg2, arg3);
        })
        .then((results) => {return doSomethingElse(arg5);
        })
        .then(() => {// do a final something})
        .catch((err) => {// errors land here});

这是因为如果 then 函数返回 Promise 对象,那么 Promⅰse 类反对链式。
async/await 个性实现 promise 类的承诺,以简化异步编码。此性能在异步函数中变为沉闷状态:

async function mumble() {// async magic happens here}

异步箭头函数如下所示:

const mumble = async () => {// async magic happens here};

为了理解异步函数范例给咱们带来了多大的改良,让咱们从新编写后面的示例,如下所示:

async function doSomething(arg1, arg2, arg3, arg4, arg5) {const { result1, result2} = await doThis(arg1, arg2); 
 const results = await doThat(arg2, arg3);
 await doSomethingElse(arg5);
 // do a final something
 return finalResult;
}

同样,咱们不须要了解代码,只须要看看它的构造。与咱们开始应用的嵌套构造相比,是不是感觉难受爽多了?
wait 关键字与 Promise 一起应用。它会主动期待承诺的解析。如果承诺解析胜利,则返回值,如果承诺解 析为谬误,则抛出该谬误。处理结果和抛出谬误都以通常的形式解决。
此示例还显示了 ES2015 的另一个性能:解构。能够应用以下代码提取对象的字段:

const {value1, value2} = {value1: "Value 1", value2: "Value 2", value3: "Value3"};

这例子演示了一个对象有三个字段,但只提取其中两个字段。
为了持续摸索 JavaScript 的提高,让咱们来看看 Babel。

正文完
 0