解析Node.js异常处理中domain模块的使用方法

NodeJS 提供了 domain 模块,可以简化异步代码的异常处理。在介绍该模块之前,我们需要首先理解“域”的概念。简单的讲,一个域就是一个 JS 运行环境,在一个运行环境中,如果一个异常没有被捕获,将作为一个全局异常被抛出。NodeJS 通过 process 对象提供了捕获全局异常的方法,示例代码如下

process.on('uncaughtException', function (err) {
  console.log('Error: %s', err.message);
});

setTimeout(function (fn) {
  fn();
});
Error: undefined is not a function

虽然全局异常有个地方可以捕获了,但是对于大多数异常,我们希望尽早捕获,并根据结果决定代码的执行路径。我们用以下 HTTP 服务器代码作为例子:

function async(request, callback) {
  // Do something.
  asyncA(request, function (err, data) {
    if (err) {
      callback(err);
    } else {
      // Do something
      asyncB(request, function (err, data) {
        if (err) {
          callback(err);
        } else {
          // Do something
          asyncC(request, function (err, data) {
            if (err) {
              callback(err);
            } else {
              // Do something
              callback(null, data);
            }
          });
        }
      });
    }
  });
}

http.createServer(function (request, response) {
  async(request, function (err, data) {
    if (err) {
      response.writeHead(500);
      response.end();
    } else {
      response.writeHead(200);
      response.end(data);
    }
  });
});

以上代码将请求对象交给异步函数处理后,再根据处理结果返回响应。这里采用了使用回调函数传递异常的方案,因此 async 函数内部如果再多几个异步函数调用的话,代码就变成上边这副鬼样子了。为了让代码好看点,我们可以在每处理一个请求时,使用 domain 模块创建一个子域(JS 子运行环境)。在子域内运行的代码可以随意抛出异常,而这些异常可以通过子域对象的 error 事件统一捕获。于是以上代码可以做如下改造:

function async(request, callback) {
  // Do something.
  asyncA(request, function (data) {
    // Do something
    asyncB(request, function (data) {
      // Do something
      asyncC(request, function (data) {
        // Do something
        callback(data);
      });
    });
  });
}

http.createServer(function (request, response) {
  var d = domain.create();

  d.on('error', function () {
    response.writeHead(500);
    response.end();
  });

  d.run(function () {
    async(request, function (data) {
      response.writeHead(200);
      response.end(data);
    });
  });
});

可以看到,我们使用.create方法创建了一个子域对象,并通过.run方法进入需要在子域中运行的代码的入口点。而位于子域中的异步函数回调函数由于不再需要捕获异常,代码一下子瘦身很多。

陷阱
无论是通过 process 对象的 uncaughtException 事件捕获到全局异常,还是通过子域对象的 error 事件捕获到了子域异常,在 NodeJS 官方文档里都强烈建议处理完异常后立即重启程序,而不是让程序继续运行。按照官方文档的说法,发生异常后的程序处于一个不确定的运行状态,如果不立即退出的话,程序可能会发生严重内存泄漏,也可能表现得很奇怪。

但这里需要澄清一些事实。JS 本身的throw..try..catch异常处理机制并不会导致内存泄漏,也不会让程序的执行结果出乎意料,但 NodeJS 并不是存粹的 JS。NodeJS 里大量的 API 内部是用 C/C++ 实现的,因此 NodeJS 程序的运行过程中,代码执行路径穿梭于 JS 引擎内部和外部,而 JS 的异常抛出机制可能会打断正常的代码执行流程,导致 C/C++ 部分的代码表现异常,进而导致内存泄漏等问题。

因此,使用 uncaughtException 或 domain 捕获异常,代码执行路径里涉及到了 C/C++ 部分的代码时,如果不能确定是否会导致内存泄漏等问题,最好在处理完异常后重启程序比较妥当。而使用 try 语句捕获异常时一般捕获到的都是 JS 本身的异常,不用担心上诉问题。

(0)

相关推荐

  • 抛弃Nginx使用nodejs做反向代理服务器

    时下不少场景,都是申请一个 VPS 主机来托管运行 Web 项目的,小弟我也不例外,购买了一个小型的 Win 03 VPS 使用着.在使用的过程中,面临一个问题,就是同一类型的服务端环境还好--但如果是一个 PHP.一个 ASP. 一个 JSP 的三种类型的服务端项目并存着,该怎么分配唯一的 80 端口呢?因为商业 WWW 网站的话,往往只能占用 80  端口,--当然,如果只是做服务的话,如接口之类的,使用其他端口就不会与 80 端口冲突了.许多开发者都会面临到 80 端口这个问题,并且实际情

  • node.js中的favicon.ico请求问题处理

    复制代码 代码如下: var http=require("http");  var server=http.createServer();  server.on("request",function(req,res){5         console.log(req.url);      res.end();  });  server.listen(1337,"127.0.0.1"); 这样的代码在请求时会出现两条请求: 第一条时URL地址为用

  • 使用nodejs中httpProxy代理时候出现404异常的解决方法

    在公司中使用nodejs构建代理服务器实现前后台分离,代码不能拿出来,然后出现httpProxy代理资源的时候老是出现404.明明被代理的接口是存在的.代码大概如下: var http = require('http'), httpProxy = require('http-proxy'); var proxy = httpProxy.createProxyServer({}); var server = http.createServer(function(req, res) { proxy.

  • 解析Node.js异常处理中domain模块的使用方法

    NodeJS 提供了 domain 模块,可以简化异步代码的异常处理.在介绍该模块之前,我们需要首先理解"域"的概念.简单的讲,一个域就是一个 JS 运行环境,在一个运行环境中,如果一个异常没有被捕获,将作为一个全局异常被抛出.NodeJS 通过 process 对象提供了捕获全局异常的方法,示例代码如下 process.on('uncaughtException', function (err) { console.log('Error: %s', err.message); });

  • node.js入门教程之querystring模块的使用方法

    querystring模块 querystring从字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析.querystring模块只提供4个方法,在我看来,这4个方法是相对应的. 这4个方法分别是querystring.parse和querystring.stringify,querystring.escape和querystring.unescape. 首先,使用querystring模块之前,需要require进来: const querystring = require("

  • Node.js 缓冲区(Buffer)模块的方法及实例分析

    二进制流是大量的二进制数据的集合.由于通常情况下二进制流的大小挺大的,因此二进制流一般不会一起运送,而会在运输前切分成小块然后逐一发送. 当数据处理单元暂时不再接收其他数据流时,剩余的数据将会被保留在缓存中,直到数据处理单元准备好接收更多数据为止. Node.js 服务器一般需要在文件系统中进行读写,而文件在存储层面而言其实都是二进制流.除此之外,Node.js 还能与 TCP 流一起使用,让 TCP 流在不可靠的互联网络上提供可靠的端到端字节流保障通信. 发送给接收者的数据流会被缓冲,直到接收

  • 在 Node.js 中使用原生 ES 模块方法解析

    从版本 8.5.0 开始,Node.js 开始支持原生 ES 模块,可以通过命令行选项打开该功能.新功能很大程度上得归功于 Bradley Farias. 1.演示 这个示例的代码目录结构如下: esm-demo/ lib.mjs main.mjs lib.mjs: export function add(x, y) { return x + y; } main.mjs: import {add} from './lib.mjs'; console.log('Result: '+add(2, 3

  • 总结Node.js中9种fs模块文件操作方法(文件夹递归删除知识)

    目录 一.前言 二.fs.mkdir()创建文件夹 2.1 最简单的案例 2.2 递归创建文件夹 三.fs.wirteFile()创建.写文件 3.1 创建并写入一个文件 3.2 重写文件并指定编码 3.3 写入GBK格式的文件 四.fs.appendFile()文件后追加内容 4.1 使用追加的方式创建并写入内容 4.2 追加内容 五.fs.stat()判断路径是目录还是文件 5.1 判断文件案例 六.fs.readFile()读取文件内容 6.1 以默认格式读取文件 6.2 以指定格式(这里

  • Node.js基础入门之path模块,url模块,http模块使用详解

    目录 path模块 1. path模块示例 2. path模块其他方法 url模块 1. 旧的解析方法 2. 新的解析方法 http模块 1. 什么是HTTP协议? 2. HTTP协议约束的细节 3. HTTP请求响应过程 4. http模块get方法 经过前面四天的学习,对Node.js已经有了一个基础的认识,今天继续学习Node.js网络通信编程相关内容,并稍加整理加以分享,如有不足之处,还请指正. path模块 Node.js中,提供了一个path模块,在这个模块中,提供了许多实用的,可被

  • 浅谈Node.js爬虫之网页请求模块

    本文介绍了Node.js爬虫之网页请求模块,分享给大家,具体如下: 注:如您下载最新的nodegrass版本,由于部分方法已经更新,本文的例子已经不再适应,详细请查看开源地址中的例子. 一.为什么我要写这样一个模块? 源于笔者想使用Node.js写一个爬虫,虽然Node.js官方API提供的请求远程资源的方法已经非常简便,具体参考 http://nodejs.org/api/http.html 其中对于Http的请求提供了,http.get(options, callback)和http.req

  • Node.js设置定时任务之node-schedule模块的使用详解

    node-schedule是 Node.js 的一个定时任务(crontab)模块.我们可以使用定时任务来对服务器系统进行维护,让其在固定的时间段执行某些必要的操作,还可以使用定时任务发送邮件.爬取数据等: 一.安装 npm install node-schedule # 或 yarn add node-schedule 二.基础用法 使用schedule.scheduleJob()即可创建一个定时任务,一个简单的上手示例: const schedule = require('node-sche

  • Node.js中的events事件模块知识点总结

    通过对Node的学习及应用,我们知道NodeJS其采用单线程.事件驱动.非阻塞I/O等架构设计,非常适用于高并发.I/O密集型应用. 1. 什么是事件驱动? 事件驱动,简单来说就是通过有效方法来监听事件状态的变化,并在发生变化时做出相应的动作. 举一个生活应用的场景来理解:当我们去饭店吃饭点餐,当我们下单之后,服务员告诉我们的订单号(这时候可以理解为注册了一个事件),我们在坐着等候,这时候我们的耳朵就一直监听着服务员的喊号,当喊到我们的时候,我们可以去前台取餐. 2. 事件模型 NodeJS的事

  • Node.js入门笔记 之async模块

    目录 前言 async series parallel waterfall map 前言 前面我们介绍了异步模块的CPS解决嵌套回调的方法,但是随着业务的推进,node的更新方法也越来越快,对于异步的处理会有更多的新的方法来解决,最常见的当然是async模块来解决异步请求,这一节就来记录一下async模块的应用,对异步的处理更进一步台阶 async async不同于ES2017的新特性,这里的async表示的是node的第三方模块,也是一个比较出名的第三方模块,为了解决异步嵌套的回调地狱的问题,

随机推荐