Javascript 为什么Node';创建(foo)比新建foo()慢得多?
我在JS中使用回溯编写了一个简单的数独解算器。为了实现“纯功能”,我的所有9x9拼图数组都是不可变的,因此每当插入一个新的数字时,就会创建一个新的数组 第1版使用新的SudokuPuzzle 在第一个版本中,我使用Javascript 为什么Node';创建(foo)比新建foo()慢得多?,javascript,node.js,Javascript,Node.js,我在JS中使用回溯编写了一个简单的数独解算器。为了实现“纯功能”,我的所有9x9拼图数组都是不可变的,因此每当插入一个新的数字时,就会创建一个新的数组 第1版使用新的SudokuPuzzle 在第一个版本中,我使用新拼图(Puzzle)方法克隆对象: function SudokuPuzzle(obj) { if (obj instanceof SudokuPuzzle) { this.grid = obj.grid.slice(0); // copy array }
新拼图(Puzzle)
方法克隆对象:
function SudokuPuzzle(obj) {
if (obj instanceof SudokuPuzzle) {
this.grid = obj.grid.slice(0); // copy array
} // ...
}
然后,每当我更新阵列时,我都会执行以下操作:
SudokuPuzzle.prototype.update = function(row, col, num) {
var puzzle = new SudokuPuzzle(this); // clone puzzle
puzzle.grid[row*9 + col] = num; // mutate clone
return puzzle; // return clone
}
版本2使用Object.create()
我编写了另一个版本,其中使用了Object.create()
,并有一个基本对象sudokuPuzzle
,我从中继承来创建新的拼图。以下是clone()
方法:
sudokuPuzzle.clone = function() {
var puzzle = Object.create(this); // create puzzle from sudokuPuzzle
puzzle.grid = this.grid.slice(0); // copy array
return puzzle; // return newly minted puzzle
}
在这种情况下,我的更新方法是
sudokuPuzzle.update = function(row, col, num) {
var puzzle = this.clone(); // clone puzzle
puzzle.grid[row*9 + col] = num; // mutate clone
return puzzle; // return clone
}
速度测试
使用new
的第一个版本使用Node时速度非常快:
$ time node Sudoku.js
real 0m0.720s
user 0m0.699s
sys 0m0.016s
使用Object.create()
的第二个版本的速度始终慢10倍以上:
$ time node Sudoku2.js
real 0m7.746s
user 0m7.647s
sys 0m0.091s
注意到Object.create()
在浏览器中的速度要慢得多,同时我也看到了与的巨大差异。我当然可以看到JS引擎之间的计时差异,但差异大于10倍?!?有人知道为什么差异超过一个数量级吗
你可以在这里找到答案
更新带注释的答案
感谢Bergi下面的回答,我将clone
方法中的行从
var puzzle = Object.create(this);
为此:
var puzzle = Object.create(sudokuPuzzle);
这避免了长而复杂的继承链(即,我总是从同一个基本对象继承),现在我可以获得与使用new
相当的速度结果。谢谢Bergi。你可以查看其他帖子,对我来说,这是直觉——如果你使用新关键字,那么引擎知道它想要创建什么。如果使用Object.create,则引擎需要执行一些额外的检查工作,覆盖类型
正如文章中所写,如果您只创建了几个对象,那么性能应该无关紧要(7秒?真的吗?)。然而-JS并不是为反射而构建的。因此,this.clone()或Object.create(this)方法确实无效。您已经确定V8无法优化
对象。create
与new
一样好(与SpiderMonkey相反)。至少在历史上是这样。另见
然而,这要慢得多还有第二个原因:您的两个代码有不同的结果。你必须使用
SudokuPuzzle.prototype.clone = function() {
var puzzle = Object.create(SudokuPuzzle.prototype); // a new instance, without `new`
puzzle.grid = this.grid.slice(0); // copy array (usually initialised in constructor)
return puzzle; // return newly minted puzzle
};
创建与使用new SudokuPuzzle()
创建的克隆等效的克隆
问题是,当您使用
Object.create(this)
时,您正在创建一个具有不同原型的新对象,即this
实例。通常情况下,相互克隆会创建一个非常复杂的继承层次结构。所有这些对象,具有不同的原型,将有不同的隐藏类-这。我对Node优化尾部递归的效果印象深刻-它们不优化对象似乎很愚蠢。创建--这是一个核心机制。实际上,回溯算法正在创建数亿个节点(想想按行大顺序填充数独谜题的所有可能性)。时间差远远超过一个完整的数量级——这不是一个很大的差异!杰出的那是票!我没有考虑复杂的继承层次结构。我想我做错了——尽可能从同一个对象继承!