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 事件监听器,效率极高。

相关推荐
焦糖小布丁3 小时前
泛域名SSL证书:一张证书保护所有子域名,企业网站必选
前端
码银3 小时前
【简易聊天室】使用 HTML、CSS、JavaScript 结合 WebSocket 技术实现
javascript·css·node.js·html
老华带你飞3 小时前
订票系统|车票管理系统|基于Java+vue的车票管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·订票系统
桃子不吃李子3 小时前
一些工具的使用
javascript·mongodb·node.js
whltaoin3 小时前
【浏览器CORS问题解决方案】SpringBoot+Vue3前后端全覆盖:浏览器跨域问题的多样化解决方案
vue.js·spring boot·浏览器跨域问题
笨笨狗吞噬者4 小时前
【uniapp】解决小程序分包下的json文件编译后生成到主包的问题
前端·uni-app
IT_陈寒4 小时前
Redis 7个性能优化技巧,让我们的QPS从5k提升到20k+
前端·人工智能·后端
.又是新的一天.4 小时前
健身房预约系统SSM+Mybatis(五、预约展示)
前端·mybatis
晴殇i5 小时前
DOM嵌套关系全解析:前端必备的4大判断方法与性能优化实战
前端·javascript·面试