您现在的位置是:亿华云 > IT科技类资讯
一篇带你了解Node.js
亿华云2025-10-02 19:04:19【IT科技类资讯】7人已围观
简介1.如何监听 Node.js 的所有函数这是一次危险的探索,但是或许某些场景下可以用到。主要想做的事情是劫持所有的 Node.js 函数,在函数执行前后,插入钩子做些事情。但是由于场景很多而且负责,劫
1.如何监听 Node.js 的篇带所有函数
这是一次危险的探索,但是篇带或许某些场景下可以用到。主要想做的篇带事情是劫持所有的 Node.js 函数,在函数执行前后,篇带插入钩子做些事情。篇带但是篇带由于场景很多而且负责,劫持的篇带风险非常高,源码库如果你使用以下代码有问题,篇带可以提个 issue。篇带以下代码可以通过预加载方式加载或者在你的篇带代码执行前加载。
module-wrap.js
const { Module } = require(module); function before(...args) { console.log(`before call function args: ${ args}`);} function after(...args) { console.log(`after call function result: ${ args}`)}const originRequire = Module.prototype.require;// hack to make console init console.log(); function newRequire(...args){ let exports = originRequire.call(this,篇带 ...args); function patch(originFunc, key = originFunc.name) { function dummy(...args) { // you can do something before the function will be executed before([key, ...args]); let result; // if the function call by new, we call by new too if (new.target) { result = new originFunc(...args); // make the constructor point to new.target instead of originFunc because new.target maybe be a subclass of originFunc result.constructor = new.target; } else { result = originFunc.call(this, ...args); } const params = [key]; if (result) { params.push(result); } // you can do something after the function have executed after(params); return result; } // we need merge the fields which is writable of originFunc into dummy for (const [key, descriptionInfo] of Object.entries(Object.getOwnPropertyDescriptors(originFunc))) { if (descriptionInfo.writable) { Object.defineProperty(dummy, key, descriptionInfo); } } // change the function name to the name of originFunc Object.defineProperty(dummy, name, { configurable: true, value: originFunc.name }); Object.defineProperty(dummy, name, { configurable: false }); // the prototype of dummy need point to originFunc.prototype dummy.prototype = originFunc.prototype; return dummy; } // wrapper all functions in export, but now we don not handle the exports recursively if (Object.prototype.toString.call(exports) === [object Object]) { for (const [key, value] of Object.entries(exports)) { if (typeof value === function) { exports[key] = patch(value, key); } } } else if (Object.prototype.toString.call(exports) === [object Function]) { exports = patch(exports); } return exports;} Module.prototype.require = newRequire;测试例子。server.js
const http = require(http); http.createServer((req,篇带 res) => { res.end(ok);}).listen(8888);执行 node -r ./module-wraper.js server.js 将会看到输出
before call function args: createServer,(req, res) => { res.end(ok);} after call function result: createServer,[object Object]你可以在钩子里做你想做的事情。
2.如何实现直接执行 ts 代码
ts-node 相信很多同学都使用过,篇带它可以直接执行 ts 模块。篇带下面的篇带代码同样可以做到。
const { Module } = require(module);const fs = require(fs);const path = require(path);const ts = require(typescript);const { compileFunction } = process.binding(contextify); Module._extensions[.ts] = function(module, filename) { const content = fs.readFileSync(filename, utf8); const { outputText } = ts.transpileModule(content, { compilerOptions: { module: ts.ModuleKind.CommonJS }}); const result = compileFunction( outputText, filename, 0, 0, undefined, false, undefined, [], [ exports, require, module, __filename, __dirname, ] ); result.function.call(this, module.exports, (...args) => module.require(...args), module, filename, path.dirname(filename));};原理很简单,主要是给 Node.js 增加一个 ts 模块的 加载器,源码下载在加载器里通过 typescript 包编译 ts 成 js,然后再调用 V8 的 compileFunction 执行 js。
3.如何写一个 js loader
Node.js 的某些框架的实现模块是在启动前会加载所有的模块成一个树状的结果,下面代码是实现这个 loader 的逻辑。
const fs = require(fs);const { relative } = require(path); function load() { return new Promise((resolve, reject) => { const root = process.cwd() + /a; const fileTree = { }; const REGEXP = /\.(js|json|node)$/; const filters = [node_modules, __tests__]; let request = 0; let done = false; function _load(currentPath) { request++; fs.readdir(currentPath, (error, dirOrFiles) => { request--; if (error) { console.error(error); if (!done) { done = true; reject(error); } } else if (dirOrFiles.length) { const absolutePaths = dirOrFiles.filter( (file) => !filters.includes(file) ).map((file) => `${ currentPath}/${ file}`); for (let i = 0; i < absolutePaths.length; i++) { const absolutePath = absolutePaths[i]; request++; fs.stat(absolutePath, (error, stat) => { request--; if (error) { console.error(error); if (!done) { done = true; reject(error); } } else { if (stat.isDirectory()) { _load(absolutePath); } else { try { if (REGEXP.test(absolutePath)) { const absolutePathWhithoutExt = absolutePath.replace(REGEXP, ); const relativePathWhithoutExt = relative(root, absolutePathWhithoutExt); const paths = relativePathWhithoutExt.split(/); let currentNode = fileTree; for (let j = 0; j < paths.length - 1; j++) { const path = paths[j]; if (typeof currentNode[path] === object && currentNode[path] !== null) { currentNode = currentNode[path]; } else { currentNode = currentNode[path] = { }; } } currentNode[paths[paths.length - 1]] = require(absolutePath); } } catch(e) { console.error(e); if (!done) { done = true; reject(e); } } } } if (!request && !done) { done = true; resolve(fileTree); } }); } } if (!request && !done) { resolve(fileTree); } }); } _load(root); });}load().then(console.log).catch(console.error);利用异步读取的方式提高速度。
github 地址:
1. https://github.com/theanarkh/Node.js-Function-Wrapper
2. https://github.com/theanarkh/tiny-ts-node
3. https://github.com/theanarkh/Node.js-Loader
云南idc服务商很赞哦!(11518)
下一篇: 如何利用边缘数据中心重塑计算的未来