js 一个神奇的尾递归优化

原文链接: js 一个神奇的尾递归优化

上一篇: 编程类最强字体 FiraCode

下一篇: 一个去中心化的免费电子书共享网站 JS解码URL和编码URL

参考

https://www.zhihu.com/question/414097020/answer/1442510541

测试代码

const getList = (size) => Array(size).fill(1);

const sum = (list) => {
  if (list.length === 1) return list[0];
  const prev = list.pop();
  return prev + sum(list);
};

const sumAsync = async (list) => {
  await undefined;
  if (list.length === 1) return list[0];
  const prev = list.pop();
  return prev + (await sumAsync(list));
};

console.log(getList(10));
sumAsync(getList(10)).then(console.log);
console.log(sum(getList(10)));

async function test(size) {
  sumAsync(getList(size)).then((data) => {
    console.log("async", data);
    console.log(sum(getList(size)));
  });
}
test(20000);

异步的可以正常执行, 但是同步的会爆栈

up-e952944455664fcbe7de2440aaadff09e5e.png

同步代码, 栈空间是O(n) 的, 在列表比较大的情况下会直接把栈内存占满后报错

up-e130e0770ed1a5fb8ca3581696823f595e9.png

异步代码, 首先直觉上也是O(n)的, 但是确实可以成功输出

up-4a009b90e5f44836006432a4d3d424d7122.png

作者的说法, 即async将栈内存转移到堆中, 由于堆内存比栈大得多, 所以即使是小数据的O(n), 堆内存也是可以撑住的

up-744e241606494fcb5d6e6fec5c872c935aa.png

左边是同步的, 执行是一样的 , 右边会变化, 也就是说转到了堆上

up-450632da420d40342302572b05d608c326b.png

两个的区别只是注释了那个优化一行导致的

const async_hooks = require("async_hooks")

let index = 0
let print_buffer = ""

/**
 * async hooks会追踪async调用,
 * 而console.log使用异步输出,
 * 所以这里使用同步方法模拟console
 */
function println(log) {
    print_buffer += log + "\n"
}

/* 创建钩子 */
async_hooks.createHook({
    init(asyncId, type, triggerAsyncId) {
        const eid = async_hooks.executionAsyncId()
        println("init: *********************************")
        println("init: triggerAsyncId " + triggerAsyncId)
        println("init: executionAsyncId " + eid)
        println("init: asyncId " + asyncId)
        println("init: type " + type)
    }
})
.enable()

/*********** 测试区 **********/
async function A() {
    
    /* 为了观察方便只执行2次 */
    println("A: runing")
    index += 1
    if (index === 2) return undefined
    
    // 有优化递归
    // await undefined
    return await A()
}
/*********** 测试区 **********/

A().then(() => {
    console.log(print_buffer)
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值