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

Node.js

Node.js 笔记

Node.js 中文文档
http://nodejs.cn/api/


问题

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'
}

nodejs启动web服务器

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); 即可。


yum安装nodejs和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

使用官方脚本添加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

yum安装nodejs

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

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

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

Node版本管理工具n

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

安装node版本管理工具n

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

安装最新稳定版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

安装最新版node

sudo n latest 安装最新版 node

安装最新LTS版node

sudo n lts 安装最新LTS版node

安装指定版本node

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

切换默认node版本

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

删除指定版本node

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


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

下一篇 Spring-Cache

阅读
评论
2.6k
阅读预计12分钟
创建日期 2019-02-10
修改日期 2021-07-18
类别

页面信息

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

评论