最近在开发一个 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 硕士在读。《Vue.js 权威指南》作者之一。学习、思考、沉淀中, 向成为顶级 JavaScript 技术栈开发者努力。