node.jsjsforce

How to ensure that one function completes before other function


I am fairly new to Node.js, and what I am trying to achieve is to have two separate functions. One for Auth and one for sending data (So that I don't run into rate login limits if I were to simply use a callback after conn.login finishes). I tried to set this up in node like this:


var _request = {
    url: '/services/data/v45.0/actions/custom/flow/Test1',
    method: 'POST',
    body: JSON.stringify({
        "inputs": [{}]
    }),
    headers: {
        "Content-Type": "application/json"
    }
};

var conn = new jsforce.Connection({
    clientId: process.env.cliendId,
    clientSecret: process.env.clientSecret,
    version: "45.0"
});

function sfdcAuth() {
    conn.login(process.env.sfdcUser, process.env.sfdcUserPass, (err, userInfo) => {
        if (err) {
            console.log(err)
        }
        conn = conn;
        console.log("Done")
    });
}

function sfdcQuery() {
    conn.request(_request, function(err, resp) {
        console.log(resp);
        console.log(err)
    });
}
sfdcAuth()
sfdcQuery()

But because js is asynchronous it runs the second function without waiting for the first function to finish.


Solution

  • The simplest way is to pass your second function as a callback to your first function, which it can call when it’s done:

    function sfdcAuth(callback) {
      conn.login(process.env.sfdcUser, process.env.sfdcUserPass, (err, userInfo) => {
        if (err) {
          console.log(err);
        }
    
        // Invoke callback when done
        callback();
      });
    }
    
    function sfdcQuery() {
      conn.request(_request, function(err, resp) {
        console.log(resp);
        console.log(err);
      });
    }
    
    // Pass second function as callback to the first
    sfdcAuth(sfdcQuery);
    

    You could also make use of promises:

    function sfdcAuth(callback) {
      return new Promise((resolve, reject) => {
        conn.login(process.env.sfdcUser, process.env.sfdcUserPass, (err, userInfo) => {
          if (err) {
            reject(err);
          }
    
          resolve(userInfo);
        });
      });
    }
    
    function sfdcQuery() {
      return new Promise((resolve, reject) => {
        conn.request(_request, function(err, resp) {
          if (err) {
            reject(err);
          }
    
          resolve(resp);
        });
      });
    }
    
    // Wait for promise to resolve before invoking second function
    sfdcAuth()
      .then(result => {
        // Do something with result
    
        return sfdcQuery();
      })
      .then(result => {
        // You can continue the chain with
        // the result from "sfdcQuery" if you want
      })
      .catch(err => {
        // Handle error
      });