一文读懂meld.js:before/around/on/afterReturning/afterThrowing/after六种通知完全解析

📅 2026/8/23 12:12:55
一文读懂meld.js:before/around/on/afterReturning/afterThrowing/after六种通知完全解析
一文读懂meld.jsbefore/around/on/afterReturning/afterThrowing/after六种通知完全解析【免费下载链接】meldAOP for JS with before, around, on, afterReturning, afterThrowing, after advice, and pointcuts项目地址: https://gitcode.com/gh_mirrors/meld1/meldmeld.js 是一款轻量的 JavaScript AOP 库让你可以非侵入式地为方法、函数甚至构造函数添加日志、缓存、计时等行为。本文将带你快速上手 meld.js Aspect-Oriented Programming面向切面编程完整解析 before、around、on、afterReturning、afterThrowing、after 六种通知Advice的用法、触发时机与执行顺序帮助你写出更干净的 JavaScript 代码。什么是 AOP为什么 JavaScript 需要它面向切面编程AOP的核心思想是把横切关注点日志、统计、缓存、事务从业务代码中抽离出来像贴纸一样贴到目标方法上而不修改原代码。没有 AOP 时你想给一个方法加日志只能改它的源码function doSomething(a, b) { console.log(called with, a, b); // 手写的日志污染了业务逻辑 return a b; }有了 meld.js业务代码保持纯净行为外挂var myObject { doSomething: function(a, b) { return a b; } }; var remover meld.after(myObject, doSomething, function(result) { console.log(myObject.doSomething returned: result); }); myObject.doSomething(1, 2); // 输出: myObject.doSomething returned: 3 remover.remove(); // 随时撤销原方法恢复如初✅ 好处一目了然非侵入原代码一个字都不用改可复用同一段日志/缓存逻辑可贴在任意多个方法上可随时开关返回的remover.remove()一键摘除如何安装与引入 meld.jsmeld.js 支持 AMDRequireJS、Node 和 RingoJS 三种环境核心代码只有一个文件 meld.js。Node 环境最常用npm install meldvar meld require(meld);浏览器 AMD 环境可通过 bower 安装bower install meld在 RequireJS 中配置 package 后define([meld], function(meld) { ... })即可使用。官方文档位于 docs/ 目录包含 API、参考手册与内置切面三篇值得收藏docs/api.md — 六种通知的完整 APIdocs/reference.md — 通知执行顺序、切点匹配详解docs/aspects.md — 内置切面trace/memoize/cache快速上手一次看懂六种通知meld.js 提供六个同名 APImeld.before、meld.around、meld.on、meld.afterReturning、meld.afterThrowing、meld.after。它们的签名基本一致meld.xxx(object, methodName, adviceFunction);下面用一个统一的示例对象逐一拆解每种通知何时执行、收到什么参数、能做什么。1. before —— 事前通知方法执行前介入meld.before(myObject, doSomething, function(a, b) { console.log(即将执行 doSomething参数是, a, b); });✅ 在原始方法执行前调用收到与目标方法相同的参数 适合参数校验、权限检查、记录入参⚠️ 不能改变返回值也不能阻止原方法执行2. on —— 同步通知紧跟原方法之后meld.on(myObject, doSomething, function(a, b) { console.log(doSomething 刚执行完); });✅ 在原方法返回后立即执行先于 afterReturning 之前的一层 around 后段代码 收到与目标方法相同的参数 概念上它伴随原方法运行常用来做即时埋点3. around —— 环绕通知六兄弟中最强大meld.around(myObject, doSomething, function(joinpoint) { console.log(方法名, joinpoint.method, 参数, joinpoint.args); var result joinpoint.proceed(); // 手动放行执行原方法 console.log(返回了, result); return result; // 可以修改返回值 });around 通知收到一个joinpoint连接点对象它是这次调用的完整描述属性含义target原方法的调用上下文thismethod方法名args原始参数数组proceed()放行执行原方法可传新参数替换原参数proceedApply([args])同上但接收数组形式参数proceedCount()统计 proceed 被调用次数可做重试around 能做其他通知做不到的三件事修改返回值—— 直接return新值修改入参——joinpoint.proceed(1, 2, 3)拦截调用—— 不调proceed()原方法根本不执行缓存就是这么实现的官方文档里经典的缓存示例见 docs/reference.md 的 Simple Caching Examplevar cache {}; meld.around(myObject, doSomething, function(methodCall) { var cacheKey methodCall.args.join(); if (cacheKey in cache) { return cache[cacheKey]; // 直接返回缓存跳过原方法 } var result methodCall.proceed(); cache[cacheKey] result; return result; });4. afterReturning —— 返回通知只关心成功返回meld.afterReturning(myObject, doSomething, function(returnValue) { console.log(计算成功结果是, returnValue); });✅ 原方法成功返回后执行唯一参数就是返回值❌ 方法抛异常时不会执行 不能修改返回值需要就换 around5. afterThrowing —— 异常通知只关心出错meld.afterThrowing(myObject, doSomething, function(exception) { console.error(出错了, exception.message); });✅ 原方法抛异常后执行唯一参数是异常对象❌ 方法正常返回时不会执行 不能吞掉异常异常会继续向上抛 适合统一错误上报、监控打点6. after —— 最终通知无论成败都执行meld.after(myObject, doSomething, function(resultOrException) { // 参数是返回值 或 异常对象类似 finally 块 console.log(执行结束); });✅ 原方法返回或抛异常后都会执行就像try/finally 参数可能是返回值也可能是异常对象可自行判断 适合释放资源、统计耗时六种通知执行顺序一张表看懂当多个通知贴在同一方法上时执行顺序有讲究before 是后进先出 LIFO其余是先进先出 FIFO。官方给出的完整示例输出顺序是1 // beforeLIFO后加的 before 先执行 2 // before 3 // aroundproceed 之前 4 // aroundproceed 之前 5 // **原始方法本体** 6 // onFIFO 7 // on 8 // aroundproceed 之后 9 // aroundproceed 之后 10 // afterReturningFIFO 11 // afterReturning 12 // afterFIFO 13 // after记忆口诀before → around 前半段 → on → 原方法 → around 后半段 → afterReturning/afterThrowing → after。完整示例代码见 docs/reference.md 的 Advice Order Example 一节。切点Pointcut一次匹配多个方法第二个参数match支持四种形式让你精准挑选要增强的方法形式示例说明字符串doSomething精确匹配单个方法名数组[a, b]匹配列表中的每个方法正则/^fetch/匹配所有以 fetch 开头的方法函数function(obj) { return names }返回方法名数组完全自定义// 给所有以 do 开头的方法统一加日志 meld.before(myObject, /^do/, function() { console.log(do 系列方法被调用了); });用 meld() 一次性组合多种通知把多个通知打包成一个切面Aspect对象用meld()一次贴上——这也是官方内置切面的写法var remover meld(myObject, doSomething, { before: function() { console.log(入参 Array.prototype.join.call(arguments)); }, afterReturning: function(result) { console.log(返回 result); }, afterThrowing: function(e) { console.error(异常 e); } });内置切面开箱即用aspect/目录提供了三个现成切面也是学习自定义切面的好范本traceaspect/trace.js自动打印方法调用/返回/抛出的入参出参带缩进层级调试利器memoizeaspect/memoize.js简单记忆化相同参数只算一次cacheaspect/cache.js可配置存储的进阶缓存支持自定义过期、容量策略var trace require(meld/aspect/trace); var traced meld(myObject, doSomething, trace()); // 调用时自动输出: // doSomething CALL [1, 2] // doSomething RETURN 3如何移除通知给对象方法添加通知时返回值都带remove()方法调用后恢复原状var remover meld.before(myObject, doSomething, function() { console.log(arguments.length); }); myObject.doSomething(1, 2, 3); // 输出 3 remover.remove(); myObject.doSomething(1, 2, 3); // 无任何输出 而给函数或构造函数添加通知时meld 返回的是一个新的包装函数原函数毫发无损——不需要移除弃用新函数即可doSomething meld.before(doSomething, function() { console.log(arguments.length); });总结六种通知怎么选通知触发时机收到参数能做什么before原方法前相同参数校验、记录入参on原方法后立即相同参数即时埋点around包裹原方法joinpoint改参数/改返回值/拦截执行afterReturning成功返回后返回值记录结果afterThrowing抛异常后异常对象错误上报after返回或抛异常后返回值或异常收尾清理类似 finally一句话选型指南只想看就用 before/afterReturning/afterThrowing想改或拦就用 around要无论如何都执行就用 after。meld.js 以极小的体积单文件 三个内置切面把 Java 世界成熟的 AOP 思想带进 JavaScript配合 test/ 目录下的完整测试用例每种通知都有独立测试文件你可以放心地在项目中落地。现在就试试给你的项目方法贴上第一个 before 日志通知吧【免费下载链接】meldAOP for JS with before, around, on, afterReturning, afterThrowing, after advice, and pointcuts项目地址: https://gitcode.com/gh_mirrors/meld1/meld创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考