JavaScript逆向Vue处理事件和捕获错误的核心逻辑

Vue处理事件和捕获错误的核心逻辑

代码

在逆向一个Vue框架的前端代码时,发现一段反复出现的代码逻辑,这里做一个探究,我们直接上代码!

javascript 复制代码
function Ue(e, t, n, r, o) {
    var i;
    try {
        (i = n ? e.apply(t, n) : e.call(t)) && !i._isVue && f(i) && !i._handled && (i.catch((function (e) {
                return Ve(e, r, o + " (Promise/async)")
            }
        )),
            i._handled = !0)
    } catch (e) {
        Ve(e, r, o)
    }
    return i
}

function at(e, t) {
    function n() {
        var e = arguments
            , r = n.fns;
        if (!Array.isArray(r))
            return Ue(r, null, arguments, t, "v-on handler");
        for (var o = r.slice(), i = 0; i < o.length; i++)
            Ue(o[i], null, e, t, "v-on handler")
    }

    return n.fns = e,
        n
}

解释

这段代码是 Vue.js 框架(很可能是 Vue 2)内部用于处理事件和捕获错误 的核心逻辑。

简而言之,at 函数创建了一个"事件调用器",而 Ue 函数是这个调用器用来安全执行具体事件处理函数(并捕获任何错误)的工具。

函数 at: 事件调用器工厂

这个函数是一个工厂函数 ,它的作用是创建一个用于 v-on 事件的包装函数(即"调用器")。这个包装函数非常巧妙,它允许 Vue 动态地添加、删除或替换事件处理器,而无需操作真实的 DOM 事件监听器。

  • function at(e, t)
    • e: 真正的事件处理器。这可以是一个函数,也可以是一个函数数组(例如 v-on:click="[handler1, handler2]")。
    • t: 相关的 Vue 实例 (vm),会传递给 Ue

逻辑分解

  1. function n() { ... }:
    • 定义了一个新函数 n (我们称之为 invoker 或 "调用器")。
    • 这个 invoker 函数是 at 最终返回的函数。它就是最终被绑定到 DOM 元素上的那个事件监听器。
  2. var e = arguments: 当 invoker 被(例如点击事件)调用时,e 会捕获所有的事件参数(比如 event 对象)。
  3. var r = n.fns
    • 这是最关键的部分。invoker 会从它自己的一个属性 .fns 上读取真正要执行的处理器
    • 这个 .fns 属性是在函数返回前被设置的。
  4. if (!Array.isArray(r)):
    • 检查 n.fns (即 r) 是不是一个数组
    • 如果不是数组(即只是一个单独的函数),就调用 Ue (错误处理执行器) 来执行这一个函数。
  5. for (...):
    • 如果 n.fns 一个数组,它会遍历这个数组。
    • var o = r.slice(): 复制数组以防止迭代过程中数组被修改。
    • Ue(o[i], null, e, t, "v-on handler"): 对数组中的每一个函数都调用 Ue 来安全地执行它。
  6. return n.fns = e, n:
    • n.fns = e: 把传入 at 的原始处理器 (e) 存储为 invoker 的一个属性 fns
    • return n: 返回这个 invoker 函数。

小结

它不直接执行事件,而是制造 并返回另一个函数(invoker)。这个 invoker 被触发时,会查找自己 .fns 属性上的"真实"处理器(或处理器数组),然后使用 Ue 去安全地执行它们。

函数 Ue: 错误处理执行器

这个函数的核心目的是安全地执行一个函数 ,并捕获它在执行过程中可能抛出的同步错误异步 (Promise) 错误

  • function Ue(e, t, n, r, o)
    • e: 要执行的目标函数 (handler)。
    • t: 执行函数时的 this 上下文。
    • n: 传递给目标函数的参数数组。
    • r: 相关的 Vue 实例 (vm),用于错误报告。
    • o: 一个信息字符串,用于描述错误的来源 (例如 "v-on handler")。

逻辑分解

  1. var i;: 声明一个变量 i,用来存放函数的执行结果。
  2. try { ... } catch (e) { ... }: 这是一个标准的 try...catch 块,用于捕获同步错误
  3. i = n ? e.apply(t, n) : e.call(t):
    • 这是实际执行函数的地方。
    • 如果 n (参数数组) 存在,就使用 e.apply(t, n) 来调用函数,并传入参数。
    • 如果 n 不存在,就使用 e.call(t) 来调用(无参数)。
    • i 被赋值为函数的返回值。
  4. i && !i._isVue && f(i) && !i._handled:
    • 这串检查是用来处理异步 (Promise) 错误的。
    • i: 检查函数是否有返回值。
    • !i._isVue: 确保返回值不是一个 Vue 实例。
    • f(i): 这是一个(未显示的)辅助函数,作用是检查 i 是否是一个 Promise
    • !i._handled: 确保这个 Promise 的错误还未被处理过。
  5. i.catch(...):
    • 如果上述所有条件都为真(即:函数返回了一个未处理的 Promise),它会给这个 Promise 挂载一个 .catch() 处理器。
    • 如果 Promise 被 reject(即发生异步错误),Ve 函数(一个全局错误处理器)会被调用,并附带上额外的信息 "(Promise/async)"。
    • i._handled = !0: 标记这个 Promise 已经被处理,防止重复捕获。
  6. catch (e):
    • 如果在执行同步函数时就出错,会立即进入这个 catch 块。
    • 调用 Ve 错误处理器,报告这个同步错误。
  7. return i:返回目标函数的原始返回值(可能是 undefined、一个值,或者那个 Promise)。

小结

它是一个健壮的函数执行器,能统一处理同步和异步 Promise 错误,并将它们报告给 Vue 的主错误处理系统 (Ve)。

它们如何协同工作

  1. 当 Vue 编译模板,遇到一个 v-on:click="myHandler" 时,它会调用 at(myHandler, vm)
  2. at 函数创建了一个 invoker 函数,并设置 invoker.fns = myHandler,然后返回这个 invoker
  3. Vue 将这个 invoker 绑定到 DOM 元素的 click 事件上。
  4. 当用户点击元素时,invoker 被触发。
  5. invoker 内部执行,它读取自己的 .fns 属性(即 myHandler)。
  6. invoker 调用 Ue(myHandler, null, arguments, vm, "v-on handler")
  7. Ue 负责在 try...catch 中执行 myHandler,并处理可能发生的任何同步或异步错误。

这种设计的最大好处是:如果 myHandler 后来改变了(例如在 data 中),Vue 只需要更新 invoker.fns = newHandler 即可,而不需要解绑和重新绑定 DOM 事件监听器,效率极高。

相关推荐
JosieBook17 小时前
【Vue】09 Vue技术——JavaScript 数据代理的实现与应用
前端·javascript·vue.js
pusheng202517 小时前
算力时代的隐形防线:数据中心氢气安全挑战与技术突破
前端·安全
Eason_Lou17 小时前
webstorm开发vue项目快捷跳转到vue文件
ide·vue.js·webstorm
起名时在学Aiifox17 小时前
前端文件下载功能深度解析:从基础实现到企业级方案
前端·vue.js·typescript
2501_9418779818 小时前
从配置热更新到运行时自适应的互联网工程语法演进与多语言实践随笔分享
开发语言·前端·python
云上凯歌18 小时前
01 ruoyi-vue-pro框架架构剖析
前端·vue.js·架构
华仔啊19 小时前
JavaScript 如何准确判断数据类型?5 种方法深度对比
前端·javascript
毕设十刻20 小时前
基于Vue的迅读网上书城22f4d(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js
程序员小寒20 小时前
从一道前端面试题,谈 JS 对象存储特点和运算符执行顺序
开发语言·前端·javascript·面试
爱健身的小刘同学20 小时前
Vue 3 + Leaflet 地图可视化
前端·javascript·vue.js