JavaScript/ES6 快速上手教程(四):Node.js用法


JavaScript/ES6 快速上手教程(四):Node.js用法

本篇目录

说明

这里主要用 node(也就是 node.js) 运行 javascript 代码,因此有必要先了解 node 的基本用法。安装方法在 运行环境 章节已经介绍过,这里不赘述。

下面的内容主要来自 Node.js Guides

运行启动

Node 默认支持用 require 指令导入模块,下面是用 node 写的一个 http 服务:

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

用 node 直接运行 .js 文件:

node ./app.js

断点调试

Node 运行时如果带有 --inspect 参数,会启动一个进程默认监听 127.0.0.1:9229,用于与调试客户端交互。每个调试进程会有一个 UUID,调试客户端用类似下面的连接接入调试进程:

ws://127.0.0.1:9229/0f2c936f-b1cd-4ac9-aab3-f63b0f33d55e

最后一段是 UUID,在 node 运行时候的会输出调试进程地址:

$ node --inspect ./app.js
Debugger listening on ws://127.0.0.1:9229/2f51127b-357c-4506-81ed-b536fa9ff455
For help, see: https://nodejs.org/en/docs/inspector
Server running at http://127.0.0.1:3000/

调试进程拥有 node 运行环境的所有权限,注意不要把调试进程的监听地址暴露到公网中。

主流的 IDE 譬如 Visual Studio Code 1.10+、Visual Studio 2017、JetBrains WebStorm 2017.1+ 等都支持接入 node 的调试进程。

命令行调试可以使用 node-inspect,支持单步调试:

$ npm install -g node-inspect
$ node-inspect ./app.js
< Debugger listening on ws://127.0.0.1:9229/3294e5af-125a-4eb1-ae41-f2c094786029
< For help, see: https://nodejs.org/en/docs/inspector
< Debugger attached.
Break on start in app.js:7
  5  * Distributed under terms of the GPL license.
  6  */
> 7 const http = require('http');
  8
  9 const hostname = '127.0.0.1';
debug>

性能分析

Node 内置了性能分析工具 profiler inside V8,运行时加上 --prof 参数启用:

node --prof app.js

加上 –prof 后,运行时会生成一个名为 isolate-0x103cee000-79976-v8.log 的文件,这个文件中记录了性能相关的数据,用下面的命令解读:

$ node --prof-process isolate-0x103cee000-79976-v8.log
Statistical profiling result from isolate-0x103cee000-79976-v8.log, (231 ticks, 6 unaccounted, 0 excluded).

 [Shared libraries]:
   ticks  total  nonlib   name
      4    1.7%          /usr/lib/system/libsystem_platform.dylib
      1    0.4%          /usr/lib/system/libsystem_malloc.dylib
      1    0.4%          /usr/lib/libc++.1.dylib

 [JavaScript]:
   ticks  total  nonlib   name

 [C++]:
   ticks  total  nonlib   name
    114   49.4%   50.7%  T __ZN2v810Int16Array9CheckCastEPNS_5ValueE
     40   17.3%   17.8%  T node::native_module::NativeModuleEnv::CompileFunction(v8::FunctionCallbackInfo<v8::Value> const&)
     14    6.1%    6.2%  T _read
     12    5.2%    5.3%  T __kernelrpc_vm_remap
      8    3.5%    3.6%  T _fcntl$NOCANCEL
      4    1.7%    1.8%  T __ZN4node7TTYWrap3NewERKN2v820FunctionCallbackInfoINS1_5ValueEEE
...

火焰图分析

可以用 perf 采集运行时的数据,然后依据采集到数据生成 火焰图,perf 是一个 Linux 工具,要在 Linux 系统上使用。

用 perf 采集运行时数据:

perf record -e cycles:u -g -- node --perf-basic-prof app.js
perf script > perfs.out

用 stackvis 生成火焰图:

# 安装方法:npm i -g stackvis 
stackvis perf < perfs.out > flamegraph.htm

如果要分析正在运行的 node 应用,可以用下面的方法,-p 指定进程号,-F99 意思是数据采集频率为每秒 99 次:

perf record -F99 -p `pgrep -n node` -g -- sleep 3

如果希望火焰图中只包含 node 的函数,在生成火焰图前用下面的命令清除非 node 函数的记录:

sed -i \
  -e "/( __libc_start| LazyCompile | v8::internal::| Builtin:| Stub:| LoadIC:|\[unknown\]| LoadPolymorphicIC:)/d" \
  -e 's/ LazyCompile:[*~]\?/ /' \
  perfs.out

更多用法见 Node.js:Flame Graphs

Node API

Node 自带了大量的模块,可以直接使用,见:Node.js v12.4.0 Documentation

同步与异步

Node 自带一些模块同时提供了同步与异步的方法,前者在调用时会阻塞到执行完成。

同步方法:

const fs = require('fs');
const data = fs.readFileSync('./file.md'); // blocks here until file is read
console.log(data);
console.log("finish"); // will run after console.log

运行输出为:

$ node ./sync.js
<Buffer 41 42 43 20 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 20 0a>
finish

异步方法:

const fs = require('fs');
fs.readFile('./file.md', (err, data) => {
  if (err) throw err;
  console.log(data);
});
console.log("finish") // will run before console.log

运行输出为:

$ node ./async.js
finish
<Buffer 41 42 43 20 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 20 0a>

上面两种方式,输出结果中 finish 出现的位置不同。

JS 代码在 node 中是单线程运行的,这一点和其它语言非常不同,要尽量使用异步的方法。

Node 的并发机制是事件驱动,可以到 The Node.js Event Loop, Timers, and process.nextTick() 中详细了解。

并发编程时的注意事项:Don’t Block the Event Loop (or the Worker Pool)

Node 定时器的原理:Timers in Node.js and beyond

Node 项目管理

Node 项目的依赖用 package.json 管理,用 npm 初始化生成:

$ mkdir 07-ES6-Async-Generator
$ cd 07-ES6-Async-Generator
$ npm init
# 根据提示填入项目名称等

用下面的命令安装依赖包,依赖被自动写入 package.json 文件中:

npm install co --save

参考

  1. 李佶澳的博客
  2. Node.js Guides
  3. 火焰图,Flame Graphs
  4. Node.js v12.4.0 Documentation

 系列教程  环境