先上代码
let loading = false;
(async () => {
    if (loading) return;
    loading = true;
    await getAll();
    loading = false;
})()
function getAll(page = 1) {
    return new Promise(async (resolve, reject) => {
        try {
            const body = await getPage(page);
            bigHandle(body); //body 很大 处理完需要及时释放掉
            //  body = null; <--- 尝试过这个 没有用
            if (page < 10) {
                await getAll(++page)
            }
            resolve();
        } catch (error) {
            reject(error);
        }
    })
}
这段代码由于 Promise 嵌套,上一个在等下一个 Promise 完成,上一个无法被释放,最初的 Promise 需要等到 page=10 的时候洋葱模型式的层层返回后释放,pm2 中看到内存一直在飙升。。
如果去掉 Promise,改成 异步回调的形式 一切正常,但是 loading 状态的改变就要写到回调里面去,不是很直观
这里是简化的代码,真实业务中还有一大堆状态 不想都丢到函数的回调去处理 太不优雅了。
请问在使用 Promise 的时候 这种情况的最佳实现是什么?
// node 节点 夜间模式阅读会更舒服 日间模式 太黑了。。
     1 
                    
                    lllllliu      2019-10-12 10:34:26 +08:00 
                    
                    为什么不直接 Promise.all 展开呢。并没有看到或者说明下一次 Promise 需要前面做什么。如果需要前者可以链式调用呀,可以及时释放。 
                 | 
            
     2 
                    
                    lqzhgood   OP @lllllliu 因为第二页需要第一页的数据,所以需要递归调用。 而且需要控制频率,所以不能 Promise.all 并发一把梭 
                 | 
            
     3 
                    
                    ahsjs      2019-10-12 10:42:56 +08:00 
                    
                    把 body 变量放外面? 
                 | 
            
     4 
                    
                    mcfog      2019-10-12 10:43:53 +08:00 via Android 
                    
                    promise 没学明白就拿 async await 来写代码就这样了 
                用 new promise 来包别的 promise 已经是反模式了,还再加上 async await 这代码没治了,从头重写吧  | 
            
     5 
                    
                    ayase252      2019-10-12 10:44:17 +08:00 
                    
                    Promise 和 async 混用感觉很奇怪....确实按#1 来说,body 在处理 getAll(page)时是不必要的。 
                ``` getPage(page) .then((body) => { bigHandle(body) }) .then(() => { getAll(++page) }, (error) => { //... }) . ```  | 
            
     6 
                    
                    yixiang      2019-10-12 10:44:22 +08:00    写 node 从不关心内存占用……感觉是伪命题。 
                但你这个可能可以这么解决。 ``` var body; for (var i = 1; i < 10; i ++) { body = await getPage(page); bigHandle(body); } ``` 为啥想不开要递归……  | 
            
     7 
                    
                    lqzhgood   OP @ahsjs 感觉不是单纯的 body 问题。body 再怎么大也就 1m 的纯文本。内存几十兆几十兆的涨。 
                主要是 Promise 整个堆栈没有释放,这个才是内存爆炸的主要原因。 但是 递归的 Promise 怎么合理的释放上一个 Promise 感觉这是个悖论了…… 所以来问问有没有这类问题的最佳实践。 难道只能回到 回调地狱 来处理了么~  | 
            
     8 
                    
                    jifengg      2019-10-12 10:47:31 +08:00 
                    
                    同意 @mcfog 说的。 
                getAll 完全可以不用 Promise,也不要用递归。里面写个 for 循环就好了。有了 await /async,完全可以把 node 异步当成同步来开发。  | 
            
     9 
                    
                    ahsjs      2019-10-12 10:51:24 +08:00 
                    
                    let loading = false; 
                (async () => { if (loading) return; loading = true; for (let i = 0; i < 10; i++) { let body = await getPage(page); bigHandle(body); //body 很大 处理完需要及时释放掉 } loading = false; })()  | 
            
     10 
                    
                    lllllliu      2019-10-12 10:52:14 +08:00 
                    
                    emmm,Page 数量是提前可以知道的么? 提前的话只需要顺序处理就可以了啊。还可以加 Delay 随意。Reduce 或者直接 for await 不行么 哈哈哈。 
                 | 
            
     11 
                    
                    knva      2019-10-12 11:05:32 +08:00 
                    
                    要么 Promise 要么 async/await   混用头一次见 
                 | 
            
     12 
                    
                    sevenzhou1218      2019-10-12 11:20:14 +08:00 
                    
                    async 返回本身就是 promise 啊,总觉得代码怪怪的。 
                 | 
            
     13 
                    
                    muru      2019-10-12 11:57:45 +08:00 
                    
                    有流程控制的时候可以试试 promise chain 
                [ ...Array(10).keys()].map(page => getPage(page)).reduce((pc, func) => { return pc.then(() => new Promise(resolve => func(resolve)), Promise.resolve()); });  | 
            
     14 
                    
                    jsq2627      2019-10-12 13:47:42 +08:00 
                    
                    https://asciinema.org/a/dKWCuCHxZ3vkxOaifb5Rlksxj 
                抛点砖。body = null 是有用的,能让内存使用减少一半,但是还是非常占用。手动触发 GC 能让内存占用维持在稳定水平  | 
            
     15 
                    
                    miloooz      2019-10-12 13:55:24 +08:00 
                    
                    let loading = false; 
                while(page<10){ if (loading) return; loading = true; await getAll(); loading = false; }  | 
            
     16 
                    
                    withoutxx      2019-10-12 14:24:28 +08:00 
                    
                    有老哥指点一下 Promise  和 async/await 怎么一起使用吗,   上面的回复让我看懵了 
                 | 
            
     17 
                    
                    yuankui      2019-10-12 14:33:08 +08:00 
                    
                    为啥不用循环,要用地递归来写一个自己若干天之后都不能理解的代码 
                 | 
            
     18 
                    
                    FrankHB      2019-10-12 14:50:06 +08:00 
                    
                    在一个没法 reify 活动记录确保显式释放又没 proper tail call 保证的玩意儿里瞎搞?想多了。 
                呵、呵: https://github.com/nodejs/CTC/issues/3 有点意义的例子: https://srfi.schemers.org/srfi-45/srfi-45.html  | 
            
     19 
                    
                    islxyqwe      2019-10-12 14:51:38 +08:00 
                    
                    怎么又是 new promise 又是 async 的, async 就是返回 promise 的语法啊 
                递归的话肯定要尾递归的,我觉得这么写就行了 let loading = false; (async () => { if (loading) return; loading = true; await getAll(); loading = false; })() async function getAll(page = 1) { const body = await getPage(page); bigHandle(body); //body 很大 处理完需要及时释放掉 if (page < 10) { return getAll(++page) } }  | 
            
     20 
                    
                    IamUNICODE      2019-10-12 14:58:10 +08:00 
                    
                    不要用递归,展开吧。。 
                 |