返回介绍

第一部分 类型和语法

第二部分 异步和性能

1.6 语句顺序

发布于 2023-05-24 16:38:21 字数 2231 浏览 0 评论 0 收藏 0

代码中语句的顺序和 JavaScript 引擎执行语句的顺序并不一定要一致。这个陈述可能看起来似乎会很奇怪,所以我们要简单解释一下。

但在此之前,以下这一点我们应该完全清楚:这门语言的规则和语法(参见本系列的《你不知道的 JavaScript(上卷)》的“作用域和闭包”部分)已经从程序的角度在语序方面规定了可预测和非常可靠的特性。所以,接下来我们要讨论的内容你应该无法在自己的 JavaScript 程序中观察到。

如果你观察到了类似于我们将要展示的编译器对语句的重排序,那么这很明显违反了规范,而这一定是由所使用的 JavaScript 引擎中的 bug 引起的——该 bug 应该被报告和修正!但是更可能的情况是,当你怀疑 JavaScript 引擎做了什么疯狂的事情时,实际上却是你自己代码中的 bug(可能是竞态条件)引起的。所以首先要检查自己的代码,并且要反复检查。通过使用断点和单步执行一行一行地遍历代码,JavaScript 调试器就是用来发现这样 bug 的最强大工具。

考虑:

var a, b;

a = 10;
b = 30;

a = a + 1;
b = b + 1;

console.log( a + b ); // 42

这段代码中没有显式的异步(除了前面介绍过的很少见的异步 I/O !),所以很可能它的执行过程是从上到下一行行进行的。

但是,JavaScript 引擎在编译这段代码之后(是的,JavaScript 是需要编译的,参见本系列的《你不知道的 JavaScript(上卷)》的“作用域和闭包”部分!)可能会发现通过(安全地)重新安排这些语句的顺序有可能提高执行速度。重点是,只要这个重新排序是不可见的,一切都没问题。

比如,引擎可能会发现,其实这样执行会更快:

var a, b;

a = 10;
a++;

b = 30;
b++;

console.log( a + b ); // 42

或者这样:

var a, b;

a = 11;
b = 31;

console.log( a + b ); // 42

或者甚至这样:

// 因为a和b不会被再次使用
// 我们可以inline,从而完全不需要它们!
console.log( 42 ); // 42

前面的所有情况中,JavaScript 引擎在编译期间执行的都是安全的优化,最后可见的结果都是一样的。

但是这里有一种场景,其中特定的优化是不安全的,因此也是不允许的(当然,不用说这其实也根本不能称为优化):

var a, b;

a = 10;
b = 30;

// 我们需要a和b处于递增之前的状态!
console.log( a * b ); // 300

a = a + 1;
b = b + 1;

console.log( a + b ); // 42

还有其他一些例子,其中编译器重新排序会产生可见的副作用(因此必须禁止),比如会产生副作用的函数调用(特别是 getter 函数),或 ES6 代理对象(参考本系列的《你不知道的 JavaScript(下卷)》的“ES6 & Beyond”部分)。

考虑:

function foo() {
  console.log( b );
  return 1;
}

var a, b, c;

// ES5.1 getter字面量语法
c = {
  get bar() {
    console.log( a );
    return 1;
  }
};

a = 10;
b = 30;

a += foo();        // 30
b += c.bar;        // 11

console.log( a + b );  // 42

如果不是因为代码片段中的语句 console.log(..) (只是作为一种方便的形式说明可见的副作用),JavaScript 引擎如果愿意的话,本来可以自由地把代码重新排序如下:

// ...

a = 10 + foo();
b = 30 + c.bar;

// ...

尽管 JavaScript 语义让我们不会见到编译器语句重排序可能导致的噩梦,这是一种幸运,但是代码编写的方式(从上到下的模式)和编译后执行的方式之间的联系非常脆弱,理解这一点也非常重要。

编译器语句重排序几乎就是并发和交互的微型隐喻。作为一个一般性的概念,清楚这一点能够使你更好地理解异步 JavaScript 代码流问题。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文