当前位置 : 首页 » 文章分类 :  开发  »  Node.js

Node.js

Node.js 学习笔记

https://nodejs.org/zh-cn

狼叔:如何正确的学习Node.js
https://github.com/i5ting/How-to-learn-node-correctly


问题

JavaScript heap out of memory

hexo g 生成博客时报错:

<--- Last few GCs --->

[9778:0x3dbc8c0]   255427 ms: Mark-sweep 905.0 (932.2) -> 897.8 (932.2) MB, 112.6 / 0.0 ms  (average mu = 0.348, current mu = 0.317) allocation failure scavenge might not succeed
[9778:0x3dbc8c0]   255578 ms: Mark-sweep 904.9 (932.2) -> 900.6 (932.9) MB, 116.3 / 0.0 ms  (average mu = 0.293, current mu = 0.230) allocation failure scavenge might not succeed


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x1374fd9]
Security context: 0x11594c7808a1 <JSObject>
    1: /* anonymous */ [0xbdb517567e1] [/home/centos/git/hexo/node_modules/htmlparser2/lib/Parser.js:~181] [pc=0x221e201d5f5c](this=0x066bc2c80699 <Parser map = 0x28c71fabe141>)
    2: /* anonymous */ [0xbdb51756051] [/home/centos/git/hexo/node_modules/htmlparser2/lib/Tokenizer.js:~702] [pc=0x221e1ff1903c](this=0x066bc2c80759 <Tokenizer map = 0x28c71fabe0f1>)
   ...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

Writing Node.js report to file: report.20210622.113552.9778.0.001.json
Node.js report completed
 1: 0x9da7c0 node::Abort() [hexo]
 2: 0x9db976 node::OnFatalError(char const*, char const*) [hexo]

原因:
内存不足

解决:

export NODE_OPTIONS="--max-old-space-size=2048"

child_process

child_process 模块提供了衍生子进程的能力

child_process(子进程)
http://nodejs.cn/api/child_process.html

exec()创建子进程执行shell命令

child_process.exec(command[, options][, callback])
创建一个shell,然后在shell里执行命令。执行完成后,将 (error, stdout, stderr) 作为参数传入回调方法

如果提供了 callback,则调用时传入参数 (error, stdout, stderr)。
当成功时,则 error 将会为 null。 当出错时,则 error 将会是 Error 的实例。
error.code 属性将会是子进程的退出码, error.signal 将会被设为终止进程的信号。 除 0 以外的任何退出码都被视为出错。

传给回调的 stdout 和 stderr 参数将会包含子进程的 stdout 和 stderr 输出。 默认情况下,Node.js 会将输出解码为 UTF-8 并将字符串传给回调。

execFile()执行shell脚本

child_process.execFile(file[, args][, options][, callback])
child_process.execFile() 函数类似于 child_process.exec(),但默认情况下不会衍生 shell。
相反,指定的可执行文件 file 会作为新进程直接地衍生,使其比 child_process.exec() 稍微更高效。
由于没有衍生 shell,因此不支持 I/O 重定向和文件通配等行为。
从node源码来看,exec()、execFile()最大的差别,就在于是否创建了shell。(execFile()内部,options.shell === false),那么,可以手动设置shell。
所以下面两种方式是等价的

var child_process = require('child_process');
var execFile = child_process.execFile;
var exec = child_process.exec;

exec('ls -al .', function(error, stdout, stderr){
    if(error){
        throw error;
    }
    console.log(stdout);
});

execFile('ls -al .', {shell: '/bin/bash'}, function(error, stdout, stderr){
    if(error){
        throw error;
    }
    console.log(stdout);
});

Error: spawn shell.sh EACCES

原因:没有执行 shell 脚本的执行权限
解决:
给启动 node 进程的用户该脚本的可执行权限即可

Error: spawn /home/centos/git/hexo/nodejs/doker_deploy.sh EACCES
    at Process.ChildProcess._handle.onexit (internal/child_process.js:264:19)
    at onErrorNT (internal/child_process.js:456:16)
    at processTicksAndRejections (internal/process/task_queues.js:80:21) {
  errno: 'EACCES',
  code: 'EACCES',
  syscall: 'spawn /home/centos/git/hexo/nodejs/doker_deploy.sh',
  path: '/home/centos/git/hexo/nodejs/doker_deploy.sh',
  spawnargs: [],
  cmd: '/home/centos/git/hexo/nodejs/doker_deploy.sh'
}

Node.js 启动 HTTP 服务器

child_process(子进程)
http://nodejs.cn/api/child_process.html

Node.js 提供了 http 模块,http 模块主要用于搭建 HTTP 服务端和客户端,使用 HTTP 服务器或客户端功能必须调用 http 模块,代码如下:

var http = require('http');

新建一个 webapp.js 文件

//引入http模块
var http = require("http");
//设置主机名
var hostName = '127.0.0.1';
//设置端口
var port = 8080;
//创建服务
var server = http.createServer(function(req, res) {
    res.setHeader('Content-Type','text/plain');
    res.end("hello nodejs");
});

server.listen(port, hostName, function(){
    console.log(`服务器运行在http://${hostName}:${port}`);
});

后台运行
nohup node webapp.js &

nodejs搭建web服务器就是这么简单!
https://blog.csdn.net/ZACH_ZHOU/article/details/72779762


nodejs启动web服务做webhooks

新建一个 webhooks.js 文件,内容如下:

// nodejs启动一个http服务监听1121端口响应webhook
var http = require('http')
var exec = require('child_process').exec

http.createServer(function (request, response) {
    // 解决中文乱码问题
    response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
    response.write(request.url + " ");
    // 该路径与git中配置的WebHooks中的路径部分需要完全匹配
    // 博客html git目录
    if(request.url === '/pull/madaimeng') {
        // 异步执行shell命令,拉取最新代码
        exec('cd /home/ec2-user/git/madaimeng && git pull', function(err,stdout,stderr) {
          if(err) {
              console.log('Git pull error: ' + stderr);
              response.write('Git pull error: ' + stderr);
          } else {
              // 这个stdout的内容就是shell结果
              console.log('Git pull done. ' + stdout);
              response.write('Git pull done. ' + stdout);
          }
          response.end();
        });
    }

    // 博客源码git目录
    if(request.url === '/pull/madaimeng_backup') {
        // 异步执行shell命令,拉取最新代码
        exec('cd /home/ec2-user/git/madaimeng_backup && git pull', function(err,stdout,stderr) {
          if(err) {
              console.log('Git pull error: ' + stderr);
              response.write('Git pull error: ' + stderr);
          } else {
              // 这个stdout的内容就是shell结果
              console.log('Git pull done. ' + stdout);
              response.write('Git pull done. ' + stdout);
          }
          response.end();
        });
    }
}).listen(1121);
console.log("Server has started.");

后台运行
nohup node webhooks.js &

在vps本地测试
curl 127.0.0.1:1121/pull/madaimeng

curl localhost:1121/pull/madaimeng

$ curl localhost:1121/pull/madaimeng
当前目录: /home/ec2-user/git/madaimeng
Git pull done. 已经是最新的。
$ curl localhost:1121/pull/madaimeng_backup
当前目录: /home/ec2-user/git/madaimeng_backup
Git pull done. 已经是最新的。

利用Github的Webhook功能和Node.js完成项目的自动部署
https://www.jianshu.com/p/e4cacd775e5b

Hexo快速搭建静态博客并实现远程VPS自动部署
https://segmentfault.com/a/1190000006745478


异步调用改同步调用

一开始这么写的代码,发现每次触发后其实并没有更新 /home/ec2-user/git/madaimeng 中的代码
后来才想到,我的两个 exec 调用都是异步的,也就是同时开始执行的,执行git pull时还处于当前目录(非/home/ec2-user/git/madaimeng目录),也就是还没cd到目标目录中,所以肯定更新不了。
解决方法:
1、把cd进入目录那一步由异步调用改为同步调用,使用 execSync 代替 exec,后来发现这样不行,因为两个 exec 开的是不同的子进程,互相独立的
2、把两个exec合并为一个,使用 && 连接cdgit pull命令。

当时代码如下:

// nodejs启动一个http服务监听1121端口响应webhook
var http = require('http')
var exec = require('child_process').exec

http.createServer(function (request, response) {
    // 解决中文乱码问题
    response.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
    // 该路径与git中配置的WebHooks中的路径部分需要完全匹配
    // 博客html git目录
    if(request.url === '/pull/madaimeng') {
        // 进入目标目录并打印目录
        exec('cd /home/ec2-user/git/madaimeng && pwd', function(err,stdout,stderr) {
          console.log('当前目录: ' + stdout);
          response.write('当前目录: ' + stdout);
        });
        // 执行命令,拉取最新代码
        exec('git pull', function(err,stdout,stderr) {
          if(err) {
              console.log('Git pull error: ' + stderr);
              response.write('Git pull error: ' + stderr);
          } else {
              // 这个stdout的内容就是shell结果
              console.log('Git pull done. ' + stdout);
              response.write('Git pull done. ' + stdout);
          }
          response.end();
        });
    }
}).listen(1121);
console.log("Server has started.");

Node.js Error: write after end 错误

nodejs 启动 web 服务中处理请求时报错

events.js:183
      throw er; // Unhandled 'error' event
      ^

Error: write after end
    at write_ (_http_outgoing.js:622:15)
    at ServerResponse.write (_http_outgoing.js:617:10)
    at /home/ec2-user/git/madaimeng_backup/webhooks.js:19:19
    at ChildProcess.exithandler (child_process.js:273:7)
    at emitTwo (events.js:126:13)
    at ChildProcess.emit (events.js:214:7)
    at maybeClose (internal/child_process.js:915:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:209:5)

报错的 webhooks.js 代码如下

// nodejs启动一个http服务监听1121端口响应webhook
var http = require('http')
var exec = require('child_process').exec

http.createServer(function (req, res) {
    // 该路径与git中配置的WebHooks中的路径部分需要完全匹配
    if(req.url === '/pull'){
        exec('pwd', function(err,stdout,stderr) {
          console.log('当前目录: ' + stdout);
        });
        // 执行命令,拉取最新代码
        exec('git pull', function(err,stdout,stderr) {
          if(err) {
              console.log('Git pull error: ' + stderr);
              res.write('Git pull error: ' + stderr);
          } else {
              // 这个stdout的内容就是shell结果
              console.log('Git pull done. ' + stdout);
              res.write('Git pull done. ' + stdout);
          }
        });
        res.end();
    }
}).listen(1121);
console.log("Server has started.");

原因是 node 中的方法调用都是异步执行后再回调的,在我的代码中,res.end();放在了exec函数之后的主进程中, exec 方法执行后回调 function 向res中写入响应体,但主流程中已经 res.end(); 了,所以肯定会出现 write after end 错误,其实是对 node 的原理不熟悉。
res.end; 放到回调方法中的 res.write(); 之后,或者直接 res.end(body); 即可。


安装 Node.js

Node.js 包含 npm,安装 Node.js 后也就有了 npm


CentOS7 yum 安装 Node.js 和 NPM

Node.js 官方安装指南:
Installing Node.js via package manager
https://nodejs.org/en/download/package-manager/

Red Hat Enterprise Linux / CentOS / Fedora 等发行版安装指南如下:
NodeSource Node.js Binary Distributions
https://github.com/nodesource/distributions/blob/master/README.md

1、使用官方脚本添加 NodeSource 源
nodejs 官方制作了添加 node 源的在线脚本,直接下载执行就行,不需要再手动添加 epel 和 remi 源了

# As root
curl -sL https://rpm.nodesource.com/setup_14.x | bash -

# No root privileges
curl -sL https://rpm.nodesource.com/setup_14.x | sudo bash -

最后会提示执行 sudo yum install -y nodejs 来安装 nodejs 和 npm

2、yum 安装 nodejs
按照安装 NodeSource 源时输出信息的提示,使用 yum 来安装 nodejs
sudo yum install -y nodejs

安装 nodejs 时自动会安装 npm 工具,完成后查看版本验证安装成功:

$ node -v
v14.8.0
$ npm -v
6.14.7

CentOS7 离线安装 Node.js

1、打开 Node.js 下载页面
https://nodejs.org/en/download
选择 prebuilt 预构建版本,x64 版本下载,得到 node-v22.15.1-linux-x64.tar.xz

2、上传到服务器,解压

mkdir -p /usr/local/nodejs
tar -xvf node-v22.15.1-linux-x64.tar.xz -C /usr/local/nodejs

3、配置环境变量
vi /etc/profile 编辑
在最后添加

export NODE_HOME=/usr/local/nodejs/node-v22.15.1-linux-x64
export PATH=$NODE_HOME/bin:$PATH

source /etc/profile 使生效


Mac brew 安装 Node.js 和 NPM

brew install node
安装 nodejs 时会自动安装包管理工具 npm,安装完后执行 npm -vnode -v 能看到各自的版本号就说明安装成功。

$ npm -v
11.3.0
$ node -v
v24.1.0

Node 版本管理工具 n

n 是一款 Node 版本管理工具,它本身也是一个 Node 模块,这个工具的名字就叫 n

安装 Node 版本管理工具 n

sudo npm install n -g 安装 node 版本管理模块 n

n stable 安装最新稳定版 Node

sudo n stable 安装最新稳定版 node

比如我当前的 node 版本是 14.8.0,稳定版是 12.18.3

$ node -v
v14.8.0
$ sudo n stable

  installing : node-v12.18.3
       mkdir : /usr/local/n/versions/node/12.18.3
       fetch : https://nodejs.org/dist/v12.18.3/node-v12.18.3-linux-x64.tar.xz
   installed : v12.18.3 to /usr/local/bin/node
      active : v14.8.0 at /bin/node

n latest 安装最新版 Node

sudo n latest 安装最新版 node

n lts 安装最新 LTS 版 Node

sudo n lts 安装最新LTS版node

n ver 安装指定版本 Node

sudo n 版本号 安装指定版本node

切换默认node版本

安装完成多个版本后,直接输入不带参数的 n 命令,会出现一个已安装版本的列表
用键盘上下键选择版本,然后回车,就可以切换默认 Node 版本。

n rm ver 删除指定版本 Node

sudo n rm 版本号 删除指定版本node


Node 版本管理工具 nvm

nvm-sh / nvm
https://github.com/nvm-sh/nvm

NVM(Node Version Manager) Node.js 版本管理工具,可在同一台机器上轻松安装、切换和管理多个 Node.js 版本,解决不同项目对 Node.js 版本的特定需求问题。

Linux/Mac 安装 nvm

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash

退出重新登录,执行 nvm 命令查看版本号

$ nvm --version
0.39.7

nvm install 安装Node

nvm install <version> 安装指定版本的 Node.js。
version 可以是具体版本号(如 18.19.0),或 latest(最新稳定版)、lts(最新 LTS 版)等标识

nvm install 18.19.0 安装指定版本
nvm install 16 安装16系列最新版
nvm install --lts 安装最新 LTS 版
nvm install node 安装最新稳定版

安装最新 LTS 版本

$ nvm install --lts
Installing latest LTS version.
Downloading and installing node v22.19.0...
Downloading https://nodejs.org/dist/v22.19.0/node-v22.19.0-linux-x64.tar.xz...
######################################################################## 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v22.19.0

安装 16.x 最新版

$ nvm install 16
Downloading and installing node v16.20.2...
Downloading https://nodejs.org/dist/v16.20.2/node-v16.20.2-linux-x64.tar.xz...
######################################################################## 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v16.20.2 (npm v8.19.4)

nvm uninstall 卸载Node

nvm uninstall 14.17.0 卸载指定的 Node.js 版本


nvm ls 已安装Node版本

nvm list 简写 nvm ls 列出所有已安装的 Node.js 版本,当前使用版本前有 -> 箭头标记

$ nvm ls
->     v16.20.2
         system
default -> 12.22.12 (-> N/A)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v16.20.2) (default)
stable -> 16.20 (-> v16.20.2) (default)
lts/* -> lts/jod (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.12 (-> N/A)
lts/fermium -> v14.21.3 (-> N/A)
lts/gallium -> v16.20.2
lts/hydrogen -> v18.20.8 (-> N/A)
lts/iron -> v20.19.5 (-> N/A)
lts/jod -> v22.19.0 (-> N/A)

nvm ls-remote 列出可安装的版本

$ nvm ls-remote
       v22.17.1   (LTS: Jod)
       v22.18.0   (LTS: Jod)
       v22.19.0   (Latest LTS: Jod)
        v23.0.0
        v23.1.0
       v23.11.1
        v24.0.0
        v24.5.0
        v24.6.0
        v24.7.0
        v24.8.0

nvm use 切换版本

nvm use <version>

nvm use v16.20.2 切换到指定版本
nvm use 18.19.0 切换到指定版本
nvm use --lts 切换到最新LTS版
nvm use node 切换到最新稳定版


nvm current 查看当前Node版本

nvm current 显示当前正在使用的 Node.js 版本号


nvm alias default 设置默认版本

nvm alias default 16.20.2 将默认版本设置为 v16.20.2


上一篇 Hexo博客(24)VPS中部署Hexo

下一篇 Spring-Cache

阅读
评论
3.5k
阅读预计17分钟
创建日期 2019-02-10
修改日期 2025-09-11
类别

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论