美文网首页基础前端
如何安全退出死循环的代码

如何安全退出死循环的代码

作者: CondorHero | 来源:发表于2022-08-11 19:32 被阅读0次
如何安全退出死循环的代码.png

抛出问题

在浏览器的终端输入代码:

while(true){}

毫无疑问,浏览器这个 Tab 立刻被卡死,当然平时写代码我们很少写这种无脑的死循环代码,但是有一种需求很能比较常见(比如避免灾难性正则回溯 等等),就是如果一段代码运行过久,为了避免它长期占用线程,耽误线程处理别的任务,我们希望能够设定一个时间,当线程跑这段代码的时候,超过设定的时间就不在执行这段代码了。

假设实现的这个函数叫 —— functionTimeout,我们大概可以这么使用。

const deadcycle = () => {
    while(true){
        console.log("I'm dead")
    }
}


functionTimeout(() => deadcycle(), { timeout });

实现 functionTimeout

如何实现 functionTimeout 呢,可以利用 Node.js V8 虚拟机 来实现,提到虚拟机不要被吓着,事实上我们只需要两个 API new vm.Script(code[, options])script.runInNewContext

演示一,注入上下文

vm.Script 函数的第一个参数是字符串(code),里面是待运行的代码,runInNewContext 第一个参数是 vm.Script 的执行上下文。

import vm from "node:vm";

// vm.Script 第一个参数是字符串,里面是待运行的代码
const script = new vm.Script('name = "CondorHero";');

const context = {};
// runInNewContext 第一个参数是 vm.Script 的执行上下文
script.runInNewContext(context);

// context = { name: 'CondorHero' }
console.log(context);

演示二,timeout

上面只是见识了 vm.ScriptrunInNewContext 的简单使用,不过要想实现 functionTimeout 我们还需要利用 runInNewContext 函数的第二个参数,它是一个对象,其中有一个属性为 timeout,它是一个整数,单位毫秒表示 vm.Script 执行 code 代码时,如果执行时间超过 timeout 就退出执行。

看个例子:

import vm from "node:vm";

// 增加一个死循环
const script = new vm.Script('while(true){};name = "CondorHero";');

const context = {};

const isTimeoutError = (error) => {
  return error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT";
};

try {
  // 增加超时时间
  script.runInNewContext(context, {
    timeout: 500,
  });
} catch (error) {
  if (isTimeoutError(error)) {
    console.warn("超时了");
  }
}

程序将抛出错误:Error: Script execution timed out after 500ms 错误的 code 为: ERR_SCRIPT_EXECUTION_TIMEOUT,但我们通过 trycatch 来吃掉了这个错误同时实现了程序超时功能。

大功告成

我们接下来简单基于,演示二的代码进行抽象即可实现 functionTimeout。

const functionTimeout = (func, timeout) => {
  const script = new vm.Script("returnVal = _func()");

  const context = {
    _func: func,
  };

  const isTimeoutError = (error) => {
    return error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT";
  };

  try {
    script.runInNewContext(context, { timeout });
  } catch (error) {
    if (isTimeoutError(error)) {
      console.warn("超时了");
    }
  }
  return context.returnVal;
};

简单调用验证下:

const deadcycle = () => {
  while (true) {}
};

const result = functionTimeout(deadcycle, 500);
console.log(result);

输出结果:

➜ node index.js
超时了
undefined

如果是正常代码就会有结果:

const normalFunc = () => {
  return "I'm normal";
};

const result = functionTimeout(normalFunc, 500);
console.log(result);

输出结果:

➜ node index.js
I'm normal

有一个库就是上面代码的实现:
function-timeout
@sindresorhus

上面演示的代码是 Node.js 中的 API,我们无法在浏览器中使用,那么怎么在浏览器中实现类似的逻辑呢。

不好意思,没有好的实现,vm-browserify 目前是 Node.js VM 模块比较好的实现,但是 vm-browserify 只是用 frame 技术来实现在浏览器中给待执行的代码 code 注入上下文而已,但对 timeout 则没有好的实现。

这实在是一大遗憾。

参考

相关文章

  • 如何安全退出死循环的代码

    抛出问题 在浏览器的终端输入代码: 毫无疑问,浏览器这个 Tab 立刻被卡死,当然平时写代码我们很少写这种无脑的死...

  • 京东:移动端主观题

    问答题 如何退出Activity?如何安全退出已调起多个Activity的Application? finish(...

  • 新项目Bug总结

    0x1 while循环退出条件要进行测试,杜绝死循环 bug代码: 0x2 避免在循环中进行new对象、尽量使用原...

  • Android知识点

    如何安全退出已调用多个Activity的Application? 1.利用ActivityContainer来管理...

  • 第一节 for循环使用(shell)

    1.for死循环 PS:执行10次后退出 2.for循环100次

  • 理解 docker 容器的退出码

    常见退出码 Exit Code 0 退出代码0表示特定容器没有附加前台进程。 该退出代码是所有其他后续退出代码的例...

  • 循环

    for循环的3个条件都是可以省略的,如果没有退出循环的判断条件,就必须使用break语句退出循环,否则就是死循环:...

  • 有人采用这样一种方式等待多个并发请求的最后完成

    在一个死循环中去检查计数器是否countDonw到了0,如果到了0,表示所有并发任务全部完成,那么死循环退出。 试...

  • Code Review都需要关注什么?

    Code Review检查清单 死循环,死锁,异步任务,线程池等 接口性能,安全性,数据一致性,并发控制 代码可读...

  • 用户如何能用信号对nginx进行控制

    在nginx启动完成后,主进程会进入一个死循环,等待着信号进行退出、重新加载配置文件、热代码替换等一系列操作,每一...

网友评论

    本文标题:如何安全退出死循环的代码

    本文链接:https://www.haomeiwen.com/subject/jketgrtx.html