MindGame
MindGame

Reputation: 1251

Async Javascript

I'm a bit confused on how to make my nodejs exit after it completes. I know what the syntax is to exit the nodejs script. But I'm having a hard time figuring out how this whole async syntax really works. So what I want to do is call process.exit() after my nodejs application has completed everything. Right now when I put it in certain places it exits the script before the script has completed.

Here is my code where I'm getting emails from the server and writing them to the database.

(async function () {
    try {
        let pool = await sql.connect(config)

        //Query the database
        let emails = await pool.request()
            .query('select uid from email')

    emails.forEach(function(email) {
    const request = pool.request();
                        request.input('uid', sql.VarChar, email.id);
                        request.input('mail_address', sql.VarChar, email.mailAddress);
                        request.input('mail_address_display_name', sql.VarChar, mail.displayName);
                        request.input('subject', sql.VarChar, mail.subject);
                        request.input('body', sql.VarChar, mail.body);
                        request.input('sent_date', sql.DateTime, mail.sentDate);
                        request.input('created_by', sql.VarChar, mail.CreatedBy);


                var saveEmail = async function() { 
                            let result = await request.query('INSERT INTO email_copy(uid, mail_address, mail_address_display_name, subject, body, sent_date, created_by) OUTPUT INSERTED.Email_ID values (@uid, @mail_address, @mail_address_display_name, @subject, @body, @sent_date, @created_by)', (err, result) => {
                                var emailId = result.recordset[0].Email_ID;
                                return result;
                            })
                        }

            var r = saveEmail();
        });
    }



    } catch (err) {
        console.log(err);
        // ... error checks
    }
})()
.then((result) =>{
   process.exit()
 });

;

Upvotes: 1

Views: 65

Answers (1)

Ovidiu Dolha
Ovidiu Dolha

Reputation: 5413

Looks like emails.forEach(.. will instantly execute whatever you define inside.

Even if you define an async function like your saveEmail, the forEach will start execution of saveEmail for each email at the same time.

So you cannot easily know when everything has finished.

A simple way to do that would be:

await Promise.all(emails.map(function(email) {
    ...
    return saveEmail();
})).then(() => process.exit());

This creates a Promise that waits for ALL the promises inside an array to finish. These promises in this case are actually all the saveEmail for each email (using map to map each email string to a Promise for executing save in this case).

BTW: saveEmail returns a Promise because it's defined async.

NOTE: this still executes saveEmail simultaneously for all emails, but now you have a controlled way to intercept when all these save are done.

You could also implement a sequential approach as such:

await emails.reduce(function(promise, email) {
    ...
    return promise.then(() => saveEmail());
}, Promise.resolve()).then(() => process.exit());

This works by chaining all saveEmail promises in a chain starting with an empty promise (Promise.resolve()) and each save will wait for the previous one before executing.

Upvotes: 1

Related Questions