JavaScript 中的代理模式

最近看了下 JavaScript 中的代理模式,私认为代理模式就是给被代理的对象做了一些访问控制相关的操作。这里的被代理的 “对象” 并不是严格意义上的对象,它可以是任何东西,包括语言层面的变量、对象、函数,甚至是业务问题,总之是一些你想隐藏在后面的东西,先让代理在前面把把关。

举个例子,项目中可能会有一些打点的需求,即上报数据,记录一些用户的操作。每次上报都会发送一个请求,如果上报的频率较高,上报的内容较多,可能就会占用较多的网络资源,影响正常的业务请求。因此我们需要实现一个功能,限制请求的频率,以及请求的数据大小,实现如下:

// 上报逻辑
function send(ids) {
    console.log(`发送请求: ${ids}`);
}

// 使用代理模式后的上报函数
const report = (function(limit) {
    let timer = null;
    let cache = [];

    // 负责调度真正的上报函数
    const helper = () => {
        if (timer) return;

        // 2s 上报一次
        timer = setTimeout(() => {
            // 从数组中提取前十个
            const ids = cache.splice(0, 10).join(",");
            send(ids);
            clearTimeout(timer);
            timer = null;
            // 如果还有任务,则继续执行
            if (cache.length > 0) {
                helper();
            }
        }, 2000);
    }

    return function(id) {
        // 每次都往队列里面追加要上报的数据
        cache.push(id);
        // 使用 helper 函数调度执行
        helper();
    }
})(10); // 一次上报 10 个对象

// 模拟页面上调用了多次 report,但两秒后才真正往后端请求一次
for (let i = 1; i <= 78; i++) {
    report(i);
}

注意,代理对象并不会影响到原对象,如果不想使用代理,那么完全可以使用原对象,因此二者最好对外暴露同样的接口,这样方便互相替换。代理模式也符合开放封闭原则,它并没有修改原对象的逻辑,但给原对象添加了新的行为。

你可能会问,这种操作不是很常见么,这就是代理模式?是的,很多时候我们就在不知不觉中使用过一些类似的解决方案,所以模式的应用不要死记硬背,不要生搬硬套,适合自己的才是最好的。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注