最近在开发一个 JSSDK 的时候有一个需求:为了检测当前环境中是否已经加载过该脚本,需要在脚本开始运行时加入一层判断,如果检测到已存在该脚本导出的变量,则终止脚本的后续运行,否则再执行后续逻辑。 那么便碰上了本文标题的问题:如何终止 JS 程序的运行?

在很多其他语言比如 PHP 当中,存在 exit 函数来中止程序的运行。很遗憾的是 JavaScript 没有。因此我们需要自己模拟出这么一个 “exit” 功能。

我们知道,break是 JavaScript 中合法的中断语句,但其只适用于循环和 switch 语句,此路不通。除了 break,JavaScript 还可以通过 return 来显示终止一个函数的执行,比如:

function foo(){
  console.log('executed');
  return;
  console.log('not executed');
}

return 语句之后的代码将不会被执行。看起来可以用这个方式来达到我们终止 JS 脚本运行的目的。

那么我们来试试看在脚本中使用 return

// index.js

console.log("OK,let's start");
console.log('first step');
console.log('second step');
return;
console.log('you cannot see me');

我们把脚本丢到浏览器里去执行一下,发现报错了,信息如下:

Uncaught SyntaxError: Illegal return statement

这里我们犯了一个严重的错误:return 只能应用于函数内部,而脚本本身并不是函数。这里大家可能很自然的想到,把脚本包裹在一个自执行匿名函数(IIFE)里不就行了。我们尝试一下:

// index.js

;(function() {
  console.log("OK,let's start");
  console.log('first step');
  console.log('second step');
  return;
  console.log('you cannot see me');

})();

浏览器的执行结果如下:

OK,let's start
first step
second step

OK,我们的目标达成,成功终止了脚本的运行。确实,将代码包裹在 IIFE 中可以随时控制脚本运行是否终止,但是这是否有点麻烦呢?固然我们有 Rollup 一类的工具可以将代码打包成为 IIFE 形式,但毕竟多一步操作,还需要对构建工具进行配置,在小项目里成本过高。而且,并不是所有需要中断程序运行的场景下都适合将代码通过 IIFE 来执行。因此,这一方式可行,但不够简洁。

实际可行的方法是利用错误来终止 JavaScript 程序的运行。这里的错误包括语法错误、变量错误、程序错误等等,我们只需要用 throw new Error() 的方式抛出错误,就能达到目的。在抛出该错误之前的代码可正常执行不受影响,而在其之后的代码则不会执行。看下例子:

// index.js

console.log("OK,let's start");
console.log('first step');
console.log('second step');
throw new Error('this is my customed error');
console.log('you cannot see me');

结果如下:

OK,目标达成。你可以在你的程序中任意想中止的地方抛出错误,然后就能达到 exit 的目的。

但是,进一步思考,为什么 JavaScript 没有提供类似其他语言的 exit 函数呢?实际上,这一切都是因为 JavaScript 是单线程语言,基于代码可以异步执行的考虑,才没有设置 exit 功能。那么,是不是在包含异步执行的代码中,我们的抛出错误的方法实际上也不能立刻终止程序呢?答案是肯定的,我们看下例子:

// index.js

console.log("OK,let's start");
console.log('first step');
console.log('second step');
setTimeout(() => {
  console.log('you still can see me');
}, 1000);
throw new Error('this is my customed error');
console.log('you cannot see me');

执行结果如下:

“you still can see me” 延迟了一秒输出,但是仍然输出了,说明我们的 throw new Error 并没有立刻中止异步代码的执行。实际上这也是必然的,感兴趣的同学可以去研究一下 JavaScript 的运行机制以及 Event Loop 相关的内容。

最后,我们得出结论,JavaScript 的主线程同步任务可以通过抛出错误的方式立即中止,但是异步任务并不会受到影响。

支付宝扫码打赏 微信打赏

坚持原创技术分享,您的支持将鼓励我继续创作!

扫描二维码,分享此文章

逆葵's Picture
逆葵

花名逆葵,刚刚毕业的北邮 CS 土著一枚。现在淘宝 FED 搬砖。《Vue.js 权威指南》作者之一。学习、思考、沉淀中,向成为顶级 JavaScript 技术栈开发者努力。