Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

setTimeout is not honored when resolving callback function in a Promise

I have a promised based function in javascript that scrolls the web page incrementally, then scroll up to the top of the page after a brief period that uses setTimeout to delay calling callback function but it seems it is being resolved immediately.

The goal is to delay the callback until the page has scrolled at the top.

Here is the code I have:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

// main scroll function
async function promiseScroll(callback = null) {
    return new Promise((resolve, reject) => {
        function pageScroll() {
            const scrollIncrement = document.body.offsetHeight / 5

            window.scrollBy({
                top: scrollIncrement,
                left: 0,
                behavior: "smooth"
            })

            let scrollDelay = setTimeout(pageScroll, 1000)

            if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
                clearTimeout(scrollDelay)
                setTimeout(resolve(promisePageUp(callback)), 2000)
            }
        }

        pageScroll()
    })
}

// scroll the page to top
async function promisePageUp(callback = null) {
    return new Promise((resolve, reject) => {
        window.scrollTo({
            top: 0,
            left: 0,
            behavior: "smooth"
        })
        // delayedCallback might not be needed
        // the invocation of callback is not delayed for some reason
        setTimeout(resolve(delayedCallback(callback)), 2000)
    })
}

// delay resolving of callback but this does not work
async function delayedCallback(callback = null) {
    return new Promise((resolve, reject) => {
        // expect the callback to be called after 2 seconds
        // issue might be because of `callback()`, but we cannot do `callback` either
        setTimeout(resolve(callback()), 2000)
    })
}

// sample callback for testing
async function callback() {
    return "callback is called!"
}

// Run promised based scroll simulation
// This is a async IIFE
(async () => {
    const value = await promiseScroll(callback)
    console.log(value)
})()

I might be missing something simple but I can’t wrap my head around this and been fiddling since yesterday. Any advice would be appreciated.

There are related questions about Promise and setTimeout but I haven’t found similar issue that answers the case I have.

Tried to do resolve(callback) but of course the callback would not be invoked and will return the function itself.

>Solution :

This line of code:

setTimeout(resolve(promisePageUp(callback)), 2000)

is calling promisePageUp(callback) immediately. The Javascript interpreter runs resolve(promisePageUp(callback)) immediately and passes the return result from that to setTimeout() which is not what you want. Instead, you want to pass a function reference to setTimeout() like this:

setTimeout(() => resolve(promisePageUp(callback)), 2000)

so that setTimeout() can call that function LATER when the timer fires.

And, same issue with this which needs the same fix:

setTimeout(resolve(callback()), 2000)
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading