zone.js如何为函数提供新执行上下文?附场景实现困惑
解决Zone上下文隔离与传递的方案
场景一:通过run(f)传递独立ctx到函数及其子函数
不用eval(f.toString())这类hack手段,推荐用闭包作用域或上下文切换的方式实现,更优雅且可靠:
方案1:私有变量+上下文切换
利用模块私有变量存储当前上下文,每次run时切换并执行函数,执行完毕恢复,确保嵌套调用也能正确隔离:
// zone模块 const zone = (() => { let currentCtx = null; function run(f) { // 创建独立上下文 const ctx = { id: Date.now(), data: {} }; // 保存上一层上下文,处理嵌套run调用 const prevCtx = currentCtx; currentCtx = ctx; try { f(); } finally { // 执行完毕恢复原上下文 currentCtx = prevCtx; } } // 供函数f内部获取当前ctx的方法 function getCtx() { return currentCtx; } return { run, getCtx }; })(); // 使用示例 function f() { console.log(zone.getCtx()); // 每次run的ctx独立 function childFunc() { console.log(zone.getCtx()); // 子函数也能拿到同一ctx } childFunc(); } zone.run(f); zone.run(f);
方案2:with作用域实现全局式访问(仅作演示,不推荐)
如果要让ctx像全局变量一样直接访问,可以用with(注意:严格模式禁用,且会影响性能):
// zone模块 function run(f) { const ctx = { id: Date.now(), data: {} }; with(ctx) { f(); } } // 使用示例 function f() { console.log(id); // 直接访问ctx属性,每次run的id不同 } run(f); run(f);
场景二:通过导入的获取器识别调用链路获取专属ctx
核心思路是在run执行时,将函数与对应ctx绑定,而非直接解析调用栈(栈解析兼容性差):
// zone模块 const zone = (() => { // 用WeakMap存储函数与ctx的绑定关系 const funcCtxMap = new WeakMap(); function run(f) { const ctx = { id: Date.now(), data: {} }; funcCtxMap.set(f, ctx); try { f(); } finally { funcCtxMap.delete(f); } } function getCtx() { // 从调用栈中提取调用者函数(简单实现,复杂场景需优化) const stack = new Error().stack.split('\n'); const callerFuncName = stack[2].match(/at (\w+)/)[1]; // 遍历绑定关系找到对应ctx for (const [func, ctx] of funcCtxMap.entries()) { if (func.name === callerFuncName) { return ctx; } } return null; } return { run, getCtx }; })(); // 使用示例 import zone from './zone.js'; function f() { console.log(zone.getCtx()); // 获取当前run对应的专属ctx } zone.run(f);
内容的提问来源于stack exchange,提问作者Siavoshkc
相关产品推荐
相关产品推荐

