戳蓝字「 Node全栈进阶 」关注我们哦!
编者注:作者是网易资深前端@金炳,当前负责网易严选自研Node框架建设工作。做过前端、后端、产品设计,是一名全栈工程师。目前致力于Node应用框架研究开发与生态建设,实践Node应用在Serverless、Faas场景下的迁移和落地,探索Service Mesh在Node应用中的价值。
有些人可能没有听过“字节码增强技术”是什么?
这个技术其实来源于Java,被一些牛逼的Java工程师掌握的核心技术之一,被用来开发一些底层的基建类工具或者平台使用。
“字节码增强技术”: 在Java字节码生成之后, 运行期 对其进行修改,增强其功能,这种方式相当于对应用程序的二进制文件进行修改。Java字节码增强主要用来提供一些现有代码没有的功能,赋能原有项目,或者增加性能等。
概括的讲:相当于我们用typescript或者javascript写的代码,编译成一个js文件或者打包后,使用了“字节码增强技术”之后,可以增强原有的代码或者修改底层的代码。例如原来写了一个node程序,通过加入这个技术之后,你可以将原有的node程序对接到分布式链路跟踪平台上,看到对应的链路情况,代码并没有改,但是你让一个简单的node项目有了链路跟踪的功能。那我把它也叫做Node的“字节码增强技术”了。
我们为了文章的可读性,贴太多代码不好,所以举一个特别简单的代码:首先我们创建一个工程
// 创建一个工程目录 mkdir test_code // 进入工程目录 cd test_code // 初始化package.json npm init -y // 安装koa的依赖 npm install koa -s
然后我们创建一个index.js
var koa = require('koa') const app = new koa(); app.use((ctx, next)=>{ ctx.body = "hello world"; }) app.listen(8000);
然后我们运行这个工程:
node index.js
然后我们就可以访问http://127.0.0.1:8000,然后就能在浏览器上看到"hello world"了。
假设上面的代码,就是我们的业务代码。
我们做基建的人,肯定最好的情况就是不去修改上面的代码。所以我们就来利用“字节码增强技术”来开发一个工具,来增强原来的代码。
我们这个工具名字:power.js
利用“字节码增强技术”,我们需要借助shimmer这个npm包(早先知道他的时候,下载还很少,现在越来越多人用了)。如下:每周下载量有105万了,说明项目底层可能都用了,大家放心使用。
我们安装一下shimmer这个依赖
npm install shimmer -S
然后power.js的代码如下:
我们比如想要增强,原先代码,我们不知道有哪些path被调用了,那我们就增强一下这个功能。
var shimmer = require('shimmer'); var http = require('http'); // 此处为了简单,http.createServer(handler) shimmer.wrap(http, "createServer", function wrapCreateServer(original){ return function wrapFunction (handler){ let newFunction = function(req, res){ console.log(req.url); return handler(req, res); } return original.call(this, newFunction); } });
上面为了简单演示,就是我们会去加强原有http模块的createServer函数,作用就是将原有的handler做一个wrap。
相当于我们不管用koa还是express,我们底层都会去调用http.createServer方法。
所以我们通过加强http.createServer的handler方法。
然后我们怎么在应用:
node -r power.js index.js
我们通过-r power.js去引入这个文件
然后我们打开浏览器http://127.0.0.1:8000/hello,然后我们能看到,命令行里面会打印了
/hello
相当于打印出了这个url。
所以我们并没有去修改原有代码,而且这个插件,我们再使用一个express的应用程序,这个我体现在这个通用性这章节
为了验证这个通用性,我们在写一个express程序,
var express = require('express'); var app = express(); app.get('/*', function (req, res) { res.send('Hello World!'); }); app.listen(3000);
然后我们也这个运行:
node -r power.js index.js
然后我们打开浏览器http://127.0.0.1:8000/hello,然后我们能看到,命令行里面会打印了
/hello
相当于打印出了这个url。
当我们组的一些开发开发了一个应用,然后我们通过“字节码增强技术”开发了一个插件,然后让组内其他成员,运行应用的时候,去-r ./xxx,就能增强原来的代码了,比如有没有内存泄漏呀,链路跟踪,每次请求的返回啊,都能去做统计。
上面这个我们举例了一个应用场景,比如其他成员开发了一个node业务项目,然后基建成员,可以去开发一个插件,让业务方成员启动的时候,加上这个参数。
最终实现:
内存泄漏统计
链路跟踪
每个请求的返回的耗时
错误捕获的上报
mysql的调用情况的一些统计
等等
上面我们演示的是node程序,他其实也能应用在前端代码中。
比如我们使用基建代码的时候,发现这个基建在某种情况下出问题了,这个时候我们就可以去做这个wrap操作。
否则等组件发包比较慢,这个时候,我们通过wrap原来的original函数,然后最终修复这个基建中出现的问题。
上面的代码中演示的代码比较简陋,只是为了让大家能更好的理解。
因为我们wrap的时候,需要去看原有函数,而且原有函数可能有多种参数情况,所以我们typescript的时候,我们就能更好的看到这个情况。防止少覆盖了一些情况。
另外大家可以查看pandora.js这个项目里面这个的使用方式,以及另外github上面去搜索这个代码片段,就能看到一些基础类的代码中,都用了这个shimmer。
像react、angular等,我们其实分析到底下,他最后就会落到那么几个最底层的原理。
那我们打开shimmer包。
打开源码地址:
https://github.com/othiym23/shimmer/blob/master/index.js
就一个文件,大家看一下就能看完了,最终这个包的最底层就是:
Object.defineProperty
如果听了之后,对你有所启发和帮助,希望能帮忙转发一下。如果有问题,请关注下面公众号,发送问题给我。