简体   繁体   中英

Does promise resolved in n-th setTimeout cause memory leak?

I can see in Chrome task manager that the tab in which following code is running eats more and more memory, and it is not released until the promise is resolved

UPDATE

Main idea here is to use a single 'low level' method which would handle "busy" responses from the server. Other methods just pass url path with request data to it and awaiting for a valuable response.

Some anti-patterns was removed.

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

The first time you call _call() in here:

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

It will not call the resolve callback and it will return a rejected promise and thus the new Promise() you have in getBalance() will just do nothing initially. Remember, since _call is marked async , when you throw, that is caught and turned into a rejected promise.

When the timer fires, it will call resolve() and that will resolve the getBalance() promise, but it will not have a value and thus you don't get your balance. By the time you do eventually call resolve(response.balance) , you've already called that resolve() function so the promise it belongs to is latched and won't change its value.


As others have said, there are all sorts of things wrong with this code (lots of anti-patterns). Here's a simplified version that works when I run it in node.js or in the snippet here in the answer:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM