【发布时间】:2015-12-04 07:25:42
【问题描述】:
让var o = {a:Date.now(), b:Date.now()}.
o.a === o.b 总是true 吗? (我对 Node.JS 最感兴趣。)
【问题讨论】:
标签: javascript node.js date datetime
让var o = {a:Date.now(), b:Date.now()}.
o.a === o.b 总是true 吗? (我对 Node.JS 最感兴趣。)
【问题讨论】:
标签: javascript node.js date datetime
没有。
你的问题暗示了两个问题:
对象初始化器是否有什么特别之处,它查看属性初始化器值并“优化”它们或避免冗余调用?
Date.now 在快速连续调用两次时是否总是返回相同的值?
答案是否定的。 :-) 让我们更详细地看一下:
对象初始化器是逐步处理的。这在规范 (start here) 中有详细说明,虽然在之前的第 5 版规范中很多更容易理解,但它基本上说创建了对象,然后将属性添加到按源代码顺序,一次一个。所以:
var o = {
a: "one",
b: "two"
};
首先,JavaScript 引擎创建对象,然后计算 a ("one") 的属性初始化器的右侧,将 a 属性与结果值相加,然后计算右侧b ("two") 的属性初始值设定项的一侧,然后将 b 属性与结果值相加。所以我们知道右侧是单独评估的,并且在过程中的不同时刻。这就是为什么:
var value = 0;
function unique() {
return value++;
}
var o = {
a: unique(),
b: unique()
};
var value = 0;
function unique() {
return value++;
}
var o = {
a: unique(),
b: unique()
};
snippet.log("o.a = " + o.a + ", o.b = " + o.b);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
...a 可靠地 得到0 和b 可靠地 得到1。
因此,我们知道:
var o = {
a: Date.now(),
b: Date.now()
};
...将连续两次调用Date.now,一个接一个。是时候看看那个了...
Date.now 快速连续调用对Date.now的两次调用,一个接一个,确实可以返回不同的值;它甚至不是那么罕见。这是一个基于时间的函数。如果您在毫秒时间更改的任一侧调用,您将获得不同的值。现在,一毫秒对计算机来说是很长的时间,但并不是所有的时间都那么。
我们可以很容易地通过经验证明它发生了:
var first, second;
var counter = 0;
snippet.log("Start");
do {
first = Date.now();
second = Date.now();
++counter;
} while (first === second);
snippet.log("Stop, values were different: " + first + " !== " + second + "; counter = " + counter);
var first, second;
var counter = 0;
snippet.log("Start");
do {
first = Date.now();
second = Date.now();
++counter;
} while (first === second);
snippet.log("Stop, values were different");
snippet.log(first + " !== " + second);
snippet.log("counter = " + counter);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
上面总是停止,证明两个快速连续的调用将返回不同的值。对我来说,在 Linux 上的 Chrome 上,counter 通常甚至都不是那么高(通常是 4 位数,有时是 3,有时是 5)。
我们也知道它发生在the specification,它说:
now函数返回一个数字值,它是指定 UTC 日期和时间的时间值调用now。
(我的重点) 因此,规范的合规实现不能在启动 JavaScript "job" 之前决定 now 的值是什么,然后在整个过程中重用它工作。这将违反规范。
因为我们知道对象初始值设定项中的属性初始值设定项是一个接一个地处理的,并且对Date.now 进行了两次单独的调用,并且我们知道对Date.now 的两次调用可能返回不同值,我们知道对于 var o = {a:Date.now(), b:Date.now()},o.a === o.b 在 NodeJS(例如 V8)或任何其他遵循规范的 JavaScript 引擎中将不始终为真。
【讨论】:
即使两者在某些 JS 引擎实现方面可能总是相等,但从逻辑上讲,这是两个不同的时刻,这就是我对待它们的方式。
【讨论】:
不,试试这个简单的测试:
var test = new Array();
for(var i=0; i<40000; i++){
test.push({a:Date.now(), b:Date.now()});
}
for(var i=0 ; i<test.length; i++){
if(test[i].a != test[i].b){
console.warn('a & b !=');
}
}
你会看到会发生什么!
【讨论】:
如果您对精度感兴趣,我建议您使用 performance.now()。 如果您需要它们相同,我建议为对象编写一个构造函数,然后将 Date.now() 分配给一个临时变量,然后将该值分配给 a 和 b。
这是 API Discovering the HR Time API 的入门介绍
这是一些特定于节点的信息:Node hrtime
【讨论】:
performance.now() 我可以得到两个不同的值!谢谢。
没有。
在我们进入规范可能会说的内容之前,Date.now 可以在运行时替换为用户定义的函数。这适用于 Node 和浏览器:
let oldNow = Date.now;
Date.now = function () {
let wait = oldNow() + 1000;
while (oldNow() < wait) {
// wait one second
}
return oldNow();
}
这样,每次调用至少需要一秒钟,所以你的两个调用永远不会相等。
当我们查看the spec for Date.now (15.9.4.4) 时,它只是说它返回
时间值,指定调用现在发生的UTC日期和时间
不保证两个调用返回相同的值。据我所知,the spec specifies that Date objects will have millisecond precision (15.9.1.1) 但不保证准确性。
很可能同一行中的两个调用可能返回相同的时间,因为底层计时器不精确并且两个调用发生在同一个刻度内,但规范没有出现指定。
【讨论】:
Date.now 可能返回两个不同值的简单证明(尽管有一段时间,Omniture 中使用了一些非常相似的代码并导致了许多问题)。