尾部调用优化javascript

尾部调用优化javascript,javascript,recursion,optimization,Javascript,Recursion,Optimization,注:这只是为了学习和提高自己。我知道可用的数组排序方法。我只是想降低总体拥有成本的基础知识 目前正在尝试使用递归进行排序算法。然而,当我试图处理大型数据集(+4000个对象)时,仍然会出现堆栈溢出错误。我正在尝试实施TCO。我对这个概念相当陌生,但我想我已经掌握了它的要点。但是,我仍然收到堆栈溢出错误 const sort = (arr, counter) => { if (!counter) { counter = arr.length - 1; } for (let

注:这只是为了学习和提高自己。我知道可用的数组排序方法。我只是想降低总体拥有成本的基础知识

目前正在尝试使用递归进行排序算法。然而,当我试图处理大型数据集(+4000个对象)时,仍然会出现堆栈溢出错误。我正在尝试实施TCO。我对这个概念相当陌生,但我想我已经掌握了它的要点。但是,我仍然收到堆栈溢出错误

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);