Challenges with using async await alongside synchronous functions

I'm currently navigating through a library that utilizes async functions and feeling a bit overwhelmed. I'm attempting to call a function that should return a string, but I'm hitting some roadblocks. As I understand it, the ZeroEx library functions all require async/await, meaning I can only call them from another async method. Does this imply that every method in my code needs to be async as well? Or am I missing something crucial?

function main() {
    var broker = zmq.socket('router');
    broker.bindSync('tcp://*:5671');


    broker.on('message', function () {
    var args = Array.apply(null, arguments)
        , identity = args[0]
        , message = args[1].toString('utf8');

        if(message === 'TopOfBook') {
            broker.send([identity, '', getTopOfBook()]);
        }

        //broker.send([identity, '', 'TEST']);
        //console.log('test sent');
    })
}

async function getTopOfBook() {
    var result: string = 'test getTopOfBook';
    const EXCHANGE_ADDRESS = await zeroEx.exchange.getContractAddress();
    const wethTokenInfo = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync('WETH');
    const zrxTokenInfo = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync('ZRX');

    if (wethTokenInfo === undefined || zrxTokenInfo === undefined) {
        throw new Error('could not find token info');
    }

    const WETH_ADDRESS = wethTokenInfo.address;
    const ZRX_ADDRESS = zrxTokenInfo.address;


    return result;
}

main();

The getTopOfBook() function isn't returning any value to the main() function, causing the result to never get sent by the broker. However, the commented out broker.send() with 'TEST' is functioning properly. Thank you for your assistance.

EDIT: I tried to make the main method async to incorporate await, but encountered an error stating that I can only use await in an async function. Could it be the broker.on() call causing this issue?

  const main = async () => {
      try{
      var broker = zmq.socket('router');
      broker.bindSync('tcp://*:5671');


      broker.on('message', function () {
      var args = Array.apply(null, arguments)
          , identity = args[0]
          , message = args[1].toString('utf8');

          console.log(message);
          if(message === 'TopOfBook') {
>>            var test = await getTopOfBook();
              console.log('in top of book test');

              broker.send([identity, '', test]);
          }

          //broker.send([identity, '', 'TEST']);
          //console.log('test sent');
      })
      } catch (err) {
          console.log(err);
      }
  }

EDIT 2: Here's my current working code. A big thank you to everyone who provided advice/solutions! I still need to complete the getTopOfBook() function to actually return a result. If you have more suggestions, please feel free to share them. I'm working on setting up a backend that fetches data from a geth rpc and sends it to a C# GUI front end.

var main = function() {
    try{
    var broker = zmq.socket('router');
    broker.bindSync('tcp://*:5672');

    broker.on('message', function () {
    var args = Array.apply(null, arguments)
        , identity = args[0]
        , message = args[1].toString('utf8');

        if(message === 'TopOfBook') {
            getTopOfBook().then((result) => {
                broker.send([identity, '', result])
            });
        }
    })
    } catch (err) {
        console.log(err);
    }
}

async function getTopOfBook() {
    var result: string = 'test getTopOfBook';
    const EXCHANGE_ADDRESS = await zeroEx.exchange.getContractAddress();
    const wethTokenInfo = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync('WETH');
    const zrxTokenInfo = await zeroEx.tokenRegistry.getTokenBySymbolIfExistsAsync('ZRX');

    if (wethTokenInfo === undefined || zrxTokenInfo === undefined) {
        throw new Error('could not find token info');
    }

    const WETH_ADDRESS = wethTokenInfo.address;
    const ZRX_ADDRESS = zrxTokenInfo.address;


    return result;
}

main();

Answer №1

It is important that the callback function is marked as asynchronous

broker.on('message', async function () {
    var args = Array.apply(null, arguments)
        , identity = args[0]
        , message = args[1].toString('utf8');

        if(message === 'TopOfBook') {
            var result = await fetchTopOfBookData();
            broker.send([identity, '', result]);
        }

        //broker.send([identity, '', 'TEST']);
        //console.log('Data sent successfully');
    })

Answer №2

It's important to understand that async functions are simply a way to write code. Under the hood, every async function actually generates a promise. This allows you to use the await keyword with any promise and seamlessly interact with libraries that utilize async functionality without needing to write async functions yourself.

When you invoke an async function, it will automatically return a promise. A promise is essentially an object with a then method, which accepts a callback to handle the resulting logic.

function main() {
    var broker = zmq.socket('router');
    broker.bindSync('tcp://*:5671');

    broker.on('message', function () {
        var args = Array.apply(null, arguments)
            , identity = args[0]
            , message = args[1].toString('utf8');

        if(message === 'TopOfBook') {
            return getTopOfBook().then(result => 
                broker.send([identity, '', result])
            ) // If the broker also returns a promise, you can continue the flow here
            .then(() => console.log('test sent'))
        }
    })
}

Personally, I'm not a fan of async/await because they can obscure the underlying nature of promises and asynchronous code.

When working with promises, always remember to return any promises you create or call so that the outer code can seamlessly continue the chain and handle any error messages.

Answer №3

Your function getTopOfBook is designed to return a Promise, which means you should utilize the then function to handle the asynchronous response.

To call this function, use the following syntax:

getTopOfBook().then((result) => {
  console.log("Result:" + result);
});

Take a Closer Look at this Code Snippet

let sleep = (fn) => {
  setTimeout(fn, 1000);
};

let getContractAddress = function(cb) {
  return new Promise((r) => sleep(() => {
    r('getContractAddress')
  }));
};

let getTokenBySymbolIfExistsAsync = function(str) {
  return new Promise((r) => sleep(() => {
    r({
      address: 'getTokenBySymbolIfExistsAsync: ' + str
    })
  }));
};

let WETH_ADDRESS = '';
let ZRX_ADDRESS = '';
let EXCHANGE_ADDRESS = '';

async function getTopOfBook() {
  var result = 'test getTopOfBook';

  const EXCHANGE_ADDRESS = await getContractAddress();
  const wethTokenInfo = await getTokenBySymbolIfExistsAsync('WETH');
  const zrxTokenInfo = await getTokenBySymbolIfExistsAsync('ZRX');

  if (wethTokenInfo === undefined || zrxTokenInfo === undefined) {
    return Promise.reject(new Error('could not find token info'));
  }

  const WETH_ADDRESS = wethTokenInfo.address;
  const ZRX_ADDRESS = zrxTokenInfo.address;

  console.log(WETH_ADDRESS);
  console.log(ZRX_ADDRESS);
  console.log(EXCHANGE_ADDRESS);

  return result;
}

var main = function() {
  console.log('Waiting response...');
  getTopOfBook().then((result) => {
    console.log("Result:" + result);
    console.log('DONE!');
  }).catch((error) => {
      console.log(error);
  });      
};

main();
.as-console-wrapper {
  max-height: 100% !important
}

If you encounter an error, you can handle it by utilizing the Promise.reject() function.

  • When calling the function, you should either pass the reject function or invoke the catch function to handle any errors.

In this example, we're demonstrating passing the reject function:

(error) => {
    console.log(error); 
}

If you don't pass the reject function, you'll need to use the catch function to manage any thrown errors.

let sleep = (fn) => {
  setTimeout(fn, 1000);
};

let getContractAddress = function(cb) {
  return new Promise((r) => sleep(() => {
    r('getContractAddress')
  }));
};

let getTokenBySymbolIfExistsAsync = function(str) {
  return new Promise((r) => sleep(() => {
    r()
  }));
};

let WETH_ADDRESS = '';
let ZRX_ADDRESS = '';
let EXCHANGE_ADDRESS = '';

async function getTopOfBook() {
  var result = 'test getTopOfBook';

  const EXCHANGE_ADDRESS = await getContractAddress();
  const wethTokenInfo = await getTokenBySymbolIfExistsAsync('WETH');
  const zrxTokenInfo = await getTokenBySymbolIfExistsAsync('ZRX');

  if (wethTokenInfo === undefined || zrxTokenInfo === undefined) {
    return Promise.reject('Could not find token info');
  }

  const WETH_ADDRESS = wethTokenInfo.address;
  const ZRX_ADDRESS = zrxTokenInfo.address;

  console.log(WETH_ADDRESS);
  console.log(ZRX_ADDRESS);
  console.log(EXCHANGE_ADDRESS);

  return result;
}

var main = function() {
  console.log('Waiting response...');
  getTopOfBook().then((result) => {
    console.log("Result:" + result);
    console.log('DONE!');
  }, (error) => {
    console.log(error); 
  }).catch((error) => {
    console.log(error); // This line will be called if reject function is missing.
  });

};

main();
.as-console-wrapper {
  max-height: 100% !important
}

Additional Resources

When invoking an async function, a Promise is returned. If the async function successfully resolves, the Promise will be resolved with the returned value. If the function encounters an exception, the Promise will be rejected with the thrown value.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leveraging Vue's "v-slot" functionality to create a specified slot within a JavaScript object

I have turned to this platform seeking guidance on using "v-slot" while utilizing a syntax that involves a javascript object. This specific method was introduced in the online course Intro to Vue3 which I recently completed. Below is an image de ...

Which is quicker when utilizing jQuery selectors: selecting by .classname or div.classname?

Which is quicker: using $(".classname"). or adding the tag to search for as well? $("div.classname") In my opinion, using just the classname would be faster because jQuery can simply loop through all classnames directly, whereas in the second example i ...

Setting up the environment variable for ApolloClient to be utilized in server-side rendering for continuous integration/continuous deployment involves following a specific

My apolloClient is configured as follows: /** * Initializes an ApolloClient instance. For configuration values refer to the following page * https://www.apollographql.com/docs/react/api/core/ApolloClient/#the-apolloclient-constructor * * @returns Apoll ...

Trouble with triggering Ajax file upload progress event

Using AJAX request, I am splitting and uploading a file in chunks. However, I have encountered an issue with the progress event not firing in Firefox. Below is the relevant code snippet: //slice file if(file.mozSlice){ chunk = file.mozSlice(startByt ...

A-Frame VR: Image missing from display on Chrome browser

UPDATE: I discovered that the issue was caused by running the HTML file from my local hard drive instead of a web server. Once I uploaded it to my web server and ran it from there, everything worked perfectly. A-Frame Version: 0.4.0, Chrome: 55.0.2883.87, ...

slider not functioning properly at the moment

I am in need of assistance with Fraction Slider from @jacksbox. I have read through the documentation multiple times, but I cannot seem to get my slider to display the effects it is meant to. The website I am working on can be found at . Here is an example ...

Angular's separate scope variables allow for isolated data manipulation within individual components

Struggling with one scope variable affecting multiple elements in a div in AngularJS. Looking for help as a beginner in handling this issue. For a clearer understanding, here's an example: JS: /* controller-home.js ********************************* ...

Tips for showing an image through a button in Angular 4

Currently, I am in the process of creating a simple website and I have encountered an issue. When I click on a button to display an image, it works fine. However, when I click on another button to display a different image, the previous image remains visib ...

The scrolling function halts as soon as the element that was middle-clicked is deleted from the

I am knee-deep in developing my own React virtualization feature and encountering a minor annoyance. When I middle click on an item in the list and start scrolling, the scrolling stops once that item is removed from the DOM. My initial thought was that the ...

tips for optimizing javascript file caching

https://i.stack.imgur.com/UhWD1.pngMy web application was created using "pug" technology about 9-8 years ago, and more recently, pages have been added in an innovative framework (vue.js). However, whenever there is a transition between an old pug page and ...

What makes Mathematics a unique object in JavaScript programming?

Recently, I've dived into learning Javascript, so pardon me if my doubts seem a bit illogical. I came across the definition for a Math object, and here is the code snippet: interface Math { /** The mathematical constant e. This is Euler's nu ...

Transforming TypeScript snapshot data in Firebase Cloud Functions into a string format for notification purposes

I've encountered the following code for cloud functions, which is intended to send a notification to the user upon the creation of a new follower. However, I'm facing an issue regarding converting the snap into a string in order to address the er ...

Need assistance with debugging the current solution for the todo App using Commander or considering a different approach with Readline and Event Emitter?

I'm currently working on developing a CLI for a Node.js exclusive todo application using the commander and conf modules within Node.js, along with chalk to add color to the output. I've encountered some issues that I'm unsure how to resolve: ...

Froala - response in JSON format for uploading images

I have integrated the Froala editor into my website. The image upload feature of this editor is functioning properly, but I am facing issues with the response. As per the documentation provided: The server needs to process the HTTP request. The server mu ...

What is the process for the event loop moving into the poll phase?

There is a scenario outlined in the event loop explanation on the Node.js official website. When setTimeout is triggered, and the callback queue for the timer phase isn't empty, why does the event loop move on to the poll phase? The site mentions that ...

Using ReactJS to display a collection of images

Currently diving into ReactJS and experimenting with the Spotify API, everything is running smoothly except for a hurdle I encountered while attempting to display an array of images retrieved from the API. I initially tried to render the images inside the ...

The issue with logging out feature

Operating an ASP.NET Web application, I have a Logout feature implemented in JavaScript. However, my current code closes the browser upon Logout, which is not the desired behavior. Instead, I am looking to clear cookies/session and redirect the user to the ...

To link the information within the angularJS controller

I've recently generated a div element dynamically within the controller function of my AngularJS application. However, I'm facing an issue where the data is not binding as expected inside this div element. Here is a snippet of my code: function ...

having difficulty sending the username and password from the HTML page to the controller in AngularJS

In my AngularJS controller, I am having trouble retrieving the values of the username and password fields after submitting the login form. Here is the HTML code for the form: <form class="form-signin" action="" method="post"> ...

Tips for efficiently storing data in the Laravel database using Ajax

I'm attempting to upload a product with multiple images to the database without refreshing the page. Despite not encountering any errors in the console, I am seeing a long block of text that starts like this: <script> Sfdump = window.Sfdump || ...