剑走偏锋!domain模块居然还能这样用!

前言

虽然domain模块目前处于弃用(Deprecated)状态。但经过我们多年来对domain模块的使用,并没有什么问题。同时node8.0之后,出现了async_hook模块,domain模块已经完全使用async_hook模块重写了,因此再也不用担心domain模块被移除后无法使用。

简单介绍domain模块

一个domain对象,可以将多个异步操作归为一组。当这些操作抛出Error事件时,domain对象可以捕捉到这些Error事件,并且不丢失上下文。

举个例子!

一般我们会用try-catch来捕捉异常,但如果在try里头有异步操作并且异步操作里抛出异常,那么这时候catch里面并不能捕捉到这个异常,比如:

这种情况在一个HTTP Server中比较常见。比如用户请求一个数据,node端接收到请求发起一个异步操作读取数据库。如果异步操作里面代码写得不够完善,抛出了异常,这时候因为无法捕捉到这个异常,所以没法拿到上下文(这里指用户的request与response)及时给用户返回错误信息。这样体验是不能接受的。

那么怎么解决这个问题呢? 可以引入domain模块。

就像图片代码所示,每一个HTTP请求来的时候创建一个domain对象。后续的操作全部在domain对象中执行,这样即使有异步操作出现异常,也能捕捉到这个异常并且不丢失上下文。

彩蛋!利用domain模块实现HTTP请求生命周期的全局变量

有仔细阅读过domain模块文档的同学可能会发现:

process.domain 这个全局变量会自动指向当前作用中的domain对象。

利用这一个特性,我们可以把一个HTTP请求生命周期内需要共享的变量挂载到domain对象上。这样在同一个请求里面的所有操作都可以通过domain对象获取到共享的变量,而再不需要通过函数参数的方式透传。

如代码所示,handle函数不需要通过外部传入res对象,也能获取到当前请求的res对象。这在代码结构非常复杂的时候非常实用!

window对象的诞生

就像浏览器环境有一个全局的window对象,TSW框架根据domain模块的特性也创建一个全局的window对象。

这里很关键的一点是利用了Object.defineProperty来创建window对象。这样window的值永远返回的是当前domain对象上的window对象。通过这种方式,在TSW框架内的编写的代码可以直接使用window变量获取到request和response对象,非常方便。

全息日志

有了一个HTTP请求声明周期的全局变量,我们实现按HTTP请求这一维度聚合日志就变得可能并且是一件很简单的事。这里直接上一张日志图:

(部分信息因安全问题做了隐藏处理)

全息日志功能支持通过用户uid快速查询用户的日志。当前这一功能也集成到tsw开放平台(tswjs.org)中,欢迎大家试用。

关于domain模块被弃用的一些思考

按nodejs的文档所说,使用domain模块之后,大家很容易就会忽略异常了。但是出现异常如果不作处理是很容易有内存泄露,这样就导致nodejs服务的不稳定。不过根据我们的实际使用, 只要每次请求结束后(包括出现异常)及时清除掉domain的引用。内存泄露的问题是不存在的。

另外根据官方文档所说,现在也没有其他方案可以完全代替domain模块,因此也不会贸然废弃domain模块。同时我们发现,从node8.0版本之后,node出现了async_hook模块,并且将domain模块用async_hook模块重写了。这意味着,以后即使官方将domain模块废弃了,第三方也可以使用async_hook模块实现一个domain模块继续使用。

所以不用担心domain会被废除,大胆的使用domain模块吧!

原文发布于微信公众号 - tswjs(tsw_service)

原文发表时间:2018-05-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

3 条评论
登录 后参与评论

相关文章

来自专栏微信公众号:Java团长

Java 异常处理的误区和经验总结

本文着重介绍了 Java 异常选择和使用中的一些误区,希望各位读者能够熟练掌握异常处理的一些注意点和原则,注意总结和归纳。只有处理好了异常,才能提升开发人员的基...

411
来自专栏史上最简单的Spring Cloud教程

Openresty最佳案例 | 第4篇:OpenResty常见的api

获取请求参数 vim /usr/example/example.conf location /lua_var { default_type ...

35911
来自专栏java工会

Java异常处理的误区和经验总结

1245
来自专栏JAVA技术站

JAVA流之DataInputStream,OutInputStream

数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后应用程序可以使用数据输入流将数据读入。

772
来自专栏alexqdjay

基于AOP动态切换数据源实现读写分离

1854
来自专栏Java 技术分享

Hibernate Session总结

3178
来自专栏大内老A

ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求

之所以称ASP.NET Core是一个Web开发平台,源于它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求。AS...

1809
来自专栏土豆专栏

Java面试之基本概念(一)

首先heap是堆,stack是栈,stack的空间是由操作系统自动分配和释放,heap的空间是手动申请和释放的;heap的空间是手动申请和释放的,heap常用n...

2397
来自专栏分布式系统和大数据处理

.Net Remoting(应用程序域) - Part.1

在互联网日渐普及,网络传输速度不断提高的情况下,分布式的应用程序是软件开发的一个重要方向。在.Net中,我们可以通过Web Service 或者Remoting...

732
来自专栏哲学驱动设计

性能优化总结(四):预加载的设计

    本节说一下数据的预加载。这节的内容与SQL没什么关系。主要说的是在 GIX4项目 中,我们是如何设计符合需求的预加载类库的。内容如下: 什么是预加载,为...

1935

扫码关注云+社区