在第n个setTimeout中是否解决了promise会导致内存泄漏?

时间:2018-02-14 21:53:13

标签: javascript memory-leaks es6-promise

我可以在Chrome任务管理器中看到运行以下代码的标签会占用越来越多的内存,并且在解析承诺之前不会发布

更新

这里的主要想法是使用单一的低级别'处理"忙"来自服务器的响应。其他方法只是将带有请求数据的url路径传递给它并等待有价值的响应。

删除了一些反模式。

var counter = 1

// emulates post requests sent with ... axios
async function post (path, data) {
    let response = (counter++ < 1000) ? { busy: true } : { balance: 3000 }
    return Promise.resolve(response)
}

async function _call (path, data, resolve) {
    let response = await post()

    if (response.busy) {
        setTimeout(() => {
            _call(path, data, resolve)
        }, 10)
        throw new Error('busy')
    }

    resolve(response.balance)
}

async function makePayment (amount) {
    return new Promise((resolve, reject) => {
        _call('/payment/create', {amount}, resolve)
    })
}

async function getBalance () {
    return new Promise((resolve, reject) => {
        _call('/balance', null, resolve)
    })
}

makePayment(500)
    .then(() => {
        getBalance()
            .then(balance => console.log('balance: ', balance))
            .catch(e => console.error('some err: ', e))
    })

1 个答案:

答案 0 :(得分:1)

您第一次在此处致电_call()

async function getBalance () {
    return new Promise((resolve, reject) => {
        _call('/balance', null, resolve)
    })
}

它不会调用resolve回调,它会返回被拒绝的承诺,因此new Promise()中的getBalance()最初将无效。请记住,因为_call被标记为async,所以当你抛出时,它会被抓住并变成被拒绝的承诺。

当计时器触发时,它会拨打resolve(),这将解析getBalance()承诺,但它没有价值,因此您无法获得余额。当您最终调用resolve(response.balance)时,您已经调用了resolve()函数,因此它所属的承诺会被锁定并且不会更改其值。

正如其他人所说,这段代码存在各种各样的错误(许多反模式)。这是一个简化版本,当我在node.js中运行它或在答案中的代码片段中时可以使用:

&#13;
&#13;
function delay(t, val) {
    return new Promise(resolve => {
        setTimeout(resolve.bind(null, val), t);
    });
}


var counter = 1;

function post() {
    console.log(`counter = ${counter}`);
    // modified counter value to 100 for demo purposes here
    return (counter++ < 100) ? { busy: true } : { balance: 3000 };
}

function getBalance () {

    async function _call() {
        let response = post();

        if (response.busy) {
            // delay, then chain next call
            await delay(10);
            return _call();
        } else {
            return response.balance;
        }
    }

    // start the whole process
    return _call();
}

getBalance()
    .then(balance => console.log('balance: ', balance))
    .catch(e => console.error('some err: ', e))
&#13;
&#13;
&#13;