Retosi
Retosi

Reputation: 45

Struggling to await in for loop

I currently have this function here

async function checkEntry(results: any) {
    let ind = 0;
    for (let i = 0; i < results.length; i++) {
        const e = results[i];

        await checkStuff(e); // returns void
        await checkOtherStuff(e); //returns void 
        await updateStatus(e); //returns void aswell

        ind++;
        await sleep(1);
    }
}

Now i would imagine that this would execute checkStuff, checkOtherStuff, updateStatus in this order and then go into the next iteration of the for-loop.

Instead it piles up promises of checkStuff and after the loop is done (console logs 10,000 of 10,000) it still gives me results of the first function called for a while.

Why does this function not run in the order I intended it to run? Or rather, why does the await keyword not block the execution of the loop for the time it takes to complete the call?

Edit: Content of the checkStuff function:

async function checkStuff(result: any) {
    
    try {
        const req = await https.get(result.url, async (res) => {
            if(res.statusCode == 404) console.log(result.url+' returns 404');
        });
        req.on("error", (e) => {
            // console.error(e);
        });
    } catch (err) {
        // console.error(err);
    }
}

Upvotes: 2

Views: 354

Answers (2)

Steve
Steve

Reputation: 4975

If you are using the await keyword, you need to use it on a promise.

Currently checkStuff isn't returning a promise so you might adapt your code to resolve the promise when the callback is executed.

const https = require('https');

function checkStuff(result) {
    return new Promise((resolve, reject) => {
        const req = https.get(result.url, (res) => {
            if (res.statusCode == 404) {
                console.log(result.url + ' returns 404');
                reject(res);
            } else {
                resolve(res);
            }
        });

        req.on('error', (e) => {
            console.error(e);
            reject(e);
        });
    }).catch((e) => {
        console.log(e);
    });
}

A callback and a Promise are different.

When a method takes a callback, it says, when I've finished this task, I'll call a function of your choice.

When you use promises, you create a Promise object and return it. It will stay as "Pending" until something inside that promise calls resolve or reject. You can pass a result into resolve or reject like this resolve(data).

Now by assigning this promise to a variable inside an async function, you have unlocked the await keyword. await will prevent your code from moving to the next line until the promise is resolved, so this helps you make your code synchronous.

async function main() {
    const result = await checkStuff();
    /* 
       Result is now a Promise object in the pending state. 
       The code will not continue past the previous line 
       until the result variable changes from pending to resolved.
    */
    
    console.log(result);
}

Upvotes: 2

t.niese
t.niese

Reputation: 40842

https.get does not provide a promise interface and await does not magically make your code wait for an asynchronous task to finish.

It is synthetic sugar to make it easier to work with Promises and requires a Promise to work.

If a function like https.get does not provide a Promise interface then you need in some way to convert it into a Promise, by e.g. wrapping a new Promise((resolve, reject) => …) around it.

const req = await new Promise((resolve, reject) => {
  https.get(result.url, async (res) => {
    if(res.statusCode == 404) console.log(result.url+' returns 404');
    resolve()
  });
  req.on("error", (e) => {
    reject(e)
  });
})

Upvotes: 1

Related Questions