Home > front end >  How to execute asynchronous code in Javascript
How to execute asynchronous code in Javascript

Time:10-06

I've looked into MDN web docs article on async functions and for some reason it doesn't work for me

Here's my code

function createObject() {
        try {
      console.log("Processing POST Loan.");
    
        var data = {
            "value1" : 1288,
            "value2" : [{
                "value3" : 3833,
                    "value4": [{
                        "value5": new Date()
                    }]
            }]      
        }
        var auth = Buffer.from("login:pass").toString('base64')
        const res = request("http://url.com/resource", {
          method: "POST",
          headers: {
            'Content-Type': 'application/json',
            'Authorization': "Basic " auth
          },
          body: JSON.stringify(data)
      }, function(error, response, body){
            //console.log(response   ' ' body)
      })
      var response = res.body.id;
      return response
   }
   catch(err) { 

    throw err
    }
}

async function uploadReport() {
    console.log('cerate object')
    var objectId = await createObject();
    console.log('object = ' objectId)
}
 uploadReport() 

Exactly as described in the article. But when I run my script I get this result:

cerate object
Processing POST Loan.
'data {"value1":1288,"value2":[{"value3":3833,"value4":[{"value5":"2021-10-05T09:45:46.126Z"}]}]}'
'auth '
object = undefined

Then nothing happens for a few seconds and execution stops. Http request works fine and objects are being created as I run the script, though I don't get any response (this API should return auto generated object ID). What am I doing wrong here?

CodePudding user response:

Let's start from the begining since you seem a little confused.

What you want to do is to make an async call from a callback kind of function ('request'). For that, you must use Promise.

So your createObject function must return a new Promise object, or must be declared as an async function. In your case, since the request function use a callback pattern, you have to use a Promise object because it will provide you a callback that must be called when your Promise resolve.


function createObject() {
    return new Promise((resolve, reject) => {
        try {
             console.log("Processing POST Loan.");
    
             var data = {
                "value1" : 1288,
                "value2" : [{
                    "value3" : 3833,
                        "value4": [{
                            "value5": new Date()
                        }]
                }]      
             }
           var auth = Buffer.from("login:pass").toString('base64')
           const res = request("http://url.com/resource", {
               method: "POST",
               headers: {
                   'Content-Type': 'application/json',
                   'Authorization': "Basic " auth
               },
               body: JSON.stringify(data)
           }, function(error, response, body){
               if(error) reject(error);
               resolve({ response, body });
           });
       }
       catch(err) { 
           reject(err);//the promise is rejected
       }
    });
}

async function uploadReport() {
    console.log('cerate object')
    const res = await createObject();
    //in res you get 'response' and 'body' where you have the result of your API.
    //it's up to you to adapt this to what you want
    console.log(res);
}

uploadReport() 

CodePudding user response:

I'm assuming you are quite new to JS programming and it seems you lack a little understanding about how the flow of execution works for async code.

In JS, async code works in promises. Promises are the way JS represents code that eventually will yield a value (or void, but it's the same).

So now we need a way to control the flow of execution. This means, we should be able to execute code that depends on that result after we have gotten that result. Or in other words, we should wait for the promise to resolve and then execute the code that depended on it.

Enter callbacks. Callbacks is how this is done in JS (before async/await appeared, but let's not get ahead of ourselves). As functions are first class citizens in JS we can declare them and pass them around as function arguments. So, in those terms, a callback it's the code that should be executed after the promise has given us its result.

When it comes to callbacks, me personally I have seen two ways of dealing with them.

A first approach, function expects such callback as an argument. Usually (but it doesn't have to be like this) the first arguments are the actual arguments necessary to perform the task, and the last one is the callback: what to do after the task is done. Example:

// A function that receives an `arguments` object and a `callback` function.
// Observe 
function doSomethingAsynchronous(arguments, callback) {
  const a = arguments.a
  const b = arguments.b

  const result = a   b //this is not asynchronous, only to illustrate.

  callback(result)
}

You would use this function like this:

doSomethingAsynchronous({a:2, b:3}, (result)=>{
  console.log(`The result was ${result}`)
})

Note how doSomethingAsynchronous does not return anything; the flow of execution is directed towards the callback.

A second approach might be a function that returns an actual Promise. Promises have a then() method and a catch() method. These are used to chain more code after the resolution of the Promise:

function iReturnAPromise(arguments) {
  return new Promise((resolve, reject) => {
    const result = arguments.a   arguments.b;
    resolve(result);

  })
}

You would manage the flow of execution by doing so:

const promiseOfTheResult = iReturnAPromise({a: 2, b:2})

promiseOfTheResult.then((result) => {console.log(result)})

// You'll never see it like that. You'll always see:

iReturnAPromise({a:2, b:3}).then((result) => {console.log(result)})

And last, but definitely not least, came async/await which simplified the use of promises. With async await, you would declare iReturnAPromise just the same, but you would use it like so;

const result = await iReturnAPromise({a:1, b:2})

console.log(result)

Notice how this last method keeps the code in line and avoids the callback hell. Also notice how functions that don't return a promise cannot be awaited, they first have to be "promisified": that is, wrapping them in a promise.

  • Related