阅读 1647

实现js熔断机制

写在前言

这是之前看到的一道面试题:

如何实现一个能强制中断死循环的方法?

想了下还是挺有意思,我们都知道,死循环可以通过break打断:

var idx=0;
while(1){
    idx++;
    if(idx>10){
        break; // 打断退出循环
    }
}

复制代码

实现:

但是如果想封装成一个函数,我是没有找到好的方法,但是我们可以使用另外一个方案,就是throw new Error() ,抛出异常,我们可以通过闭包来存储执行函数的次数,规定如果超过多少次则认定为死循环,抛出异常:

function fusing(){
    let idx = 0;
    return function(){
        idx++;
        if(idx>1000){
            idx=0;
            throw new Error('强制熔断');
        }
    }
}

复制代码

来尝试下,跑一个死循环:

let fus = fusing();
while(1){
    fus(); //Uncaught Error: 强制熔断
}

复制代码

能够正常工作,当然我们可以继续完善这个函数,改成使用时间戳和计数配合的方式,比如:

function fusing(options={times:100,timer:10000}){
    let {times,timer} = options;
    let idx = 0;
    let start = new Date().getTime(); // 获取当前时间戳
    return function(){
        idx++;
        let end = new Date().getTime(); //获取执行时间
        if(idx>times||end-start >= timer){ //10秒后执行或者idx大于100次执行
            idx=0;
            start = null;
            throw new Error('强制熔断');
        }
    }
}    

复制代码

或者把它丢到方法的原型对象里面

Function.prototype.fusing = function (options = { times: 100, timer: 10000 }) {
  let { times, timer } = options;
  let idx = 0;
  let start = new Date().getTime(); // 获取当前时间戳
  const thisArgs = this
  return function () {
    thisArgs.apply(null, arguments);
    idx++;
    let end = new Date().getTime(); //获取执行时间
    if (idx>=times||end - start >= timer) { //10秒后执行或者idx大于100次执行
      idx = 0;
      start = null;
      throw new Error('强制熔断');
    }
  }
}  
复制代码

调用的时候就可以自行使用函数

function say(w){
    console.log(w);
}
var s = say.fusing();
while(1){
    s('测试');
}

复制代码

写在最后

其实,我能想到的在现实业务中的使用场景,也只有为了防止某些可能存在死循环或者在防止某些调用次数过多的函数导致页面爆栈的情况下使用,不过也可以作为一个扩充了解,万一面试中问到呢?

关注下面的标签,发现更多相似文章
评论