尾部调用优化javascript
注:这只是为了学习和提高自己。我知道可用的数组排序方法。我只是想降低总体拥有成本的基础知识 目前正在尝试使用递归进行排序算法。然而,当我试图处理大型数据集(+4000个对象)时,仍然会出现堆栈溢出错误。我正在尝试实施TCO。我对这个概念相当陌生,但我想我已经掌握了它的要点。但是,我仍然收到堆栈溢出错误尾部调用优化javascript,javascript,recursion,optimization,Javascript,Recursion,Optimization,注:这只是为了学习和提高自己。我知道可用的数组排序方法。我只是想降低总体拥有成本的基础知识 目前正在尝试使用递归进行排序算法。然而,当我试图处理大型数据集(+4000个对象)时,仍然会出现堆栈溢出错误。我正在尝试实施TCO。我对这个概念相当陌生,但我想我已经掌握了它的要点。但是,我仍然收到堆栈溢出错误 const sort = (arr, counter) => { if (!counter) { counter = arr.length - 1; } for (let
const sort = (arr, counter) => {
if (!counter) {
counter = arr.length - 1;
}
for (let n = 1; n <= counter; n++) {
if(arr[n - 1] < arr[n]) {
let placeHolder = arr[n];
arr[n] = arr[n - 1];
arr[n - 1] = placeHolder;
}
}
counter -= 1;
return counter === 0 ? arr : sort(arr, counter);
};
function sortRecursive(arr) {
return sort(arr);
}
const sort=(arr,计数器)=>{
如果(!计数器){
计数器=阵列长度-1;
}
对于(让n=1;n为什么需要递归(它永远无法处理4000多个元素,因为这超出了每个调用堆栈)?您不能:
const sort = (arr) => {
var counter = arr.length;
while(counter-->0){
for (let n = 1; n <= counter; n++) {
if(arr[n - 1] < arr[n]) {
let placeHolder = arr[n];
arr[n] = arr[n - 1];
arr[n - 1] = placeHolder;
}
}
}
return arr;
}
顺便说一句,更简单、更快(因为它是本机实现的):
为什么您需要递归(它永远不会与4000+个元素一起工作,因为这超过了每个调用堆栈)?您不能:
const sort = (arr) => {
var counter = arr.length;
while(counter-->0){
for (let n = 1; n <= counter; n++) {
if(arr[n - 1] < arr[n]) {
let placeHolder = arr[n];
arr[n] = arr[n - 1];
arr[n - 1] = placeHolder;
}
}
}
return arr;
}
顺便说一句,更简单、更快(因为它是本机实现的):
正如您可能知道的,尾部调用优化是一种编译器技术,它允许程序无限递归,因为每次递归调用不分配更多内存
Javascript目前未进行尾部调用优化,但语言规范的ES2015标准包含TCO。每次函数在Javascript中调用自身时,都会创建一个新的堆栈框架,分配新内存,因此它最终会耗尽并崩溃
有一些技术可以避免这种情况,包括但不使用递归循环。但目前,您不能在Javascript中无限递归。正如您可能知道的,尾部调用优化是一种编译器技术,它允许程序通过不为每个递归调用分配更多内存来无限递归
Javascript目前未进行尾部调用优化,但语言规范的ES2015标准包含TCO。每次函数在Javascript中调用自身时,都会创建一个新的堆栈框架,分配新内存,因此它最终会耗尽并崩溃
有一些技术可以避免这种情况,包括但不使用递归循环。但目前在Javascript中不能无限递归。你确定你得到了尾部调用优化吗
下面是对您更新代码的测试。我唯一更改的是:
添加了'use strict';
以将代码置于严格模式。将来支持TCO的某些浏览器可能需要严格模式才能使用TCO
添加了console.trace()
以打印每个sort()调用上的调用堆栈
将测试阵列设置更改为使用Math.floor()
而不是Math.ceil()
,原因如我在上面的评论中所述
将数组长度更改为10
在运行代码段之前打开开发人员控制台并观察调用堆栈跟踪
我在最新版本的Chrome 59.0.3071.109、Firefox 54.0和Edge 15.15063中对此进行了测试。所有这些版本的堆栈跟踪都显示每次调用时调用堆栈都在增长,这表明没有尾部调用优化
为了好玩,我还在Chrome上试用了length=100000
。它运行了很长一段时间,大概一分钟左右,然后当堆栈达到大约10257次调用的深度时,由于堆栈溢出而失败。相比之下,标准的排序(函数(a,b){return b-a;})
大约在5秒钟内完成
这是一个很好的例子。文章提到的一点是,通过使用--harmony\u tailcalls
命令行开关以及'use strict';
可以在node.js中获得TCO
“严格使用”;
常量排序=(arr,计数器)=>{
console.trace();
如果(!计数器){
计数器=阵列长度-1;
}
对于(设n=1;n您确定您得到了尾部调用优化吗
下面是对您更新代码的测试。我唯一更改的是:
添加了'use strict';
以将代码置于严格模式。将来支持TCO的某些浏览器可能需要严格模式才能使用TCO
添加了console.trace()
以打印每个sort()调用上的调用堆栈
将测试阵列设置更改为使用Math.floor()
而不是Math.ceil()
,原因如我在上面的评论中所述
将数组长度更改为10
在运行代码段之前打开开发人员控制台并观察调用堆栈跟踪
我在最新版本的Chrome 59.0.3071.109、Firefox 54.0和Edge 15.15063中对此进行了测试。所有这些版本的堆栈跟踪都显示每次调用时调用堆栈都在增长,这表明没有尾部调用优化
为了好玩,我还在Chrome上试用了length=100000
。它运行了很长一段时间,大概一分钟左右,然后当堆栈达到大约10257次调用的深度时,由于堆栈溢出而失败。相比之下,标准的排序(函数(a,b){return b-a;})
大约在5秒钟内完成
这是一个很好的例子。文章提到的一点是,通过使用--harmony\u tailcalls
命令行开关以及'use strict';
可以在node.js中获得TCO
“严格使用”;
常量排序=(arr,计数器)=>{
console.trace();
如果(!计数器){
计数器=阵列长度-1;
}
for(设n=1;n您称之为TCO的是什么?能否给出输入/输出示例?@Ced no Array.sort()您使用的是哪个JavaScript引擎?TCO可能没有在您使用的JavaScript引擎中实际实现。您可以验证这一点。请注意,它不在Chrome、Firefox或任何Node.js版本中。您正在使用递归实现冒泡排序?这是您计划在生产中使用的代码吗?JavaScript没有定义为提供尾部调用操作优化。你使用的JS引擎是不是说它提供了TCO?你称之为TCO的是什么?你能
const sort = (arr) => {
var counter = arr.length;
while(counter-->0){
for (let n = 1; n <= counter; n++) {
if(arr[n - 1] < arr[n]) {
let placeHolder = arr[n];
arr[n] = arr[n - 1];
arr[n - 1] = placeHolder;
}
}
}
return arr;
}
setTimeout(sort,0,arr,counter);//instead of sort(arr,counter);
arr.sort((a,b)=>a-b);