Node.js
Node.js 学习笔记
狼叔:如何正确的学习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
合并为一个,使用 &&
连接cd
和git 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 来安装 nodejssudo 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 -v
和 node -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
下一篇 Spring-Cache
页面信息
location:
protocol
: host
: hostname
: origin
: pathname
: href
: document:
referrer
: navigator:
platform
: userAgent
: