Promise + 闭包实现函数加锁解锁

616 阅读2分钟

同事大番薯说请假几天,人走之后领导说其实是离职了,留下的代码我来接手......面对一团毛线团,我是无语凝噎。

在维护期间,发现一个需求是在 Select 存在选中的 Option 时再切换需要提示用户会清空关联数据,是否确认切换。

大番薯原来的逻辑是维护了一个 state { isLock: Boolean },在切换时先检查 isLock,默认为 false 不提示正常切换,选中后置为 true,再切换就提示,确认切换再重置为 false

这种方法也不是不行,但是想到之前读 qiankun 源码看到根据 Promise 状态确定其生命周期执行流程的那段代码,我打算把函数锁定执行这个逻辑提取成一个方法。在我打算动手之前正好在 B 站看到一个新人 up 上传了一个完整的 demo promise 加锁与解锁。所以直接拿来用了,完善了一些小细节。以下为具体步骤。

首先,该方法希望可以锁定、解锁和执行被传入的任一函数。

function lockPlant() {
  const fnMap = {};

  return function(fn) {
    fnMap[fn.name] = {
      callback: fn,

      lock: function() {},

      unLock: function() {},

      [fn.name]: function() {
        this.callback && this.callback();
      }
    };

    return fnMap[fn.name];
  }
};

其次,锁定功能和解锁使用 Promise 的延迟执行。

function lockPlant() {
  const fnMap = {};

  return function(fn) {
    fnMap[fn.name] = {
      callback: fn,

      lock: function() {
        new Promise(_resolve => {
          this.resolve = _resolve;
        })
      },

      unLock: function() {
        this.resolve();
      },

      [fn.name]: function() {
        this.callback && this.callback();
      }
    };

    return fnMap[fn.name];
  }
};

将锁定、解锁功能和原函数关联起来。

function lockPlant() {
  const fnMap = {};

  return function(fn) {
    fnMap[fn.name] = {
      callback: fn,

      lock: function() {
        this.status = new Promise(_resolve => {
          this.resolve = _resolve;
        })
      },

      unLock: function() {
        this.resolve();
      },

      [fn.name]: function() {
        if(this.status) {
          this.status.then(() => {
            this.callback && this.callback();
            this.status = null;
          })
        } else {
          this.callback && this.callback();
        }
      }
    };

    return fnMap[fn.name];
  }
};

添加检测是否被锁定函数功能和被传入的函数接收传入参数。

function lockPlant() {
  const fnMap = {};

  return function(fn) {
    fnMap[fn.name] = {
      callback: fn,

      isLock: function(){
        return !!this.status;
      },

      lock: function() {
        this.status = new Promise(_resolve => {
          this.resolve = _resolve;
        })
      },

      unLock: function() {
        this.resolve();
      },

      [fn.name]: function(...arg) {
        if(this.status) {
          this.status.then(() => {
            this.callback && this.callback(...arg);
            this.status = null;
          })
        } else {
          this.callback && this.callback(...arg);
        }
      }
    };

    return fnMap[fn.name];
  }
};

写个测试函数检测一下

const lockInstance = lockPlant();

function test(msg) {
  console.log(`hello ${msg}`);
}

const t = lockInstance(test);

t.test("word"); // 立即执行

t.lock();

t.test("word again"); // 延迟 3 秒后执行

if(t.isLock()) {
  setTimeout(() => {
    t.unLock();
  }, 3000);
}

搞定,收工。