DEV Community

bacloud14
bacloud14

Posted on

Help me make some JS functions asynchronous

Hello fellas,

Someone could help me making some functions asynchronous?
It's a Nodejs project.

Please see the issue here

Thanks a lot and I love you.

Discussion (7)

Collapse
sargalias profile image
Spyros Argalias

Here's one example of where you could have asynchronous function.

Currently, you're using a mock database which you set up yourself. It works synchronously. However, most databases you would use in production projects would take a long time to respond. They would work asynchronously. They would have some API that allows you to wait for it asynchronously. Most likely, they'll return a promise.

For example, in the helper_data.js file, your db.get function might look like this in a real codebase:

db.get = function get(query, keys, subListing = global.listings) {
  logger_.log({level: 'info', message: 'get'});
  const dataPromise = myDatabase.find('somequery'); // myDatabase.find() would return a promise
  return dataPromise;
};
Enter fullscreen mode Exit fullscreen mode

In terms of the database code you have right now, an easy thing to do might be to: keep most of your code the same, but return a promise. For example:

db.get = function get(query, keys, subListing = global.listings) {
  logger_.log({level: 'info', message: 'get'});
  return Promise.resolve(lo.pick(lo(subListing).find(query), keys)); // just wrap the data you're returning already into a promise with this line. This simulates what a real database package would return
};
Enter fullscreen mode Exit fullscreen mode

Then, in functions that use that code, you would need to handle those promises.

For example, in routes/index.js:

router.get('/tag/:tag', function(req, res, next) {
  const tag = req.params.tag;
  db.toPublic() // returns a promise, so use .then to execute the remaining code
    .then(listings => {
        return db.fetchByTag(tag, listings);
    }) // also returns a promise, so use .then again
    .then(listings => {
        res.render('index', {
            title: tag,
            user: req.session.user,
            listings: listings,
            scripts: JSVersionMappings,
        });
    })
});

// or, alternative syntax with async await.
// This is equivalent to the above, but does the .then behind the scenes
// It doesn't work on older versions of Node, so be careful
router.get('/tag/:tag', async function(req, res, next) {
  const tag = req.params.tag;
  let listings = await db.toPublic();
  listings = await db.fetchByTag(tag, listings);
  res.render('index', {
    title: tag,
    user: req.session.user,
    listings: listings,
    scripts: JSVersionMappings,
  });
});
Enter fullscreen mode Exit fullscreen mode

Of course, if you change your mock database functions to use promises, you'll break the code that uses those database functions. You'll need to update all of it to handle the promises properly.

In a real codebase, you would start with everything asynchronous, so this wouldn't be a problem. Or, your database client would have both synchronous and asynchronous functions, so you could change them one-by-one in your code without breaking everything else.

Hope this helps.

Collapse
bacloud14 profile image
bacloud14 Author

I sincerely appreciate this valuable response ! Clear and helpful.

I used async functions as you said before when working with databases, but when I started this project, I didn't know really how to implement it, I think now I know exactly what to do, and it seems easy which is great !!
(calling code in routes is really clear and in general has no particular logic, so it won't change a lot).

So thanks again !!

Collapse
bacloud14 profile image
bacloud14 Author

I have a question on the "async" method, I thought it is blocking, which defeats the purpose or am I wrong, won't it block the main thread in NodeJS ?

Collapse
sargalias profile image
Spyros Argalias

You're welcome. I'm glad it's helpful :).

Async / await only blocks the code in the specific function. While it's "awaiting", it frees up the main thread so it can do other work. When the code it's waiting on completes (for example, when db.toPublic() has completed its asynchronous operation), and when the main thread is free again, execution inside that function resumes. If it hits another "await" statement, the process repeats (it frees up the main thread and waits for the asynchronous operation to complete).

It actually uses promises behind the scenes, so it has the same effect. In the examples above with the .then and async, they both do the same thing and handle the main thread the same way.

Thread Thread
bacloud14 profile image
bacloud14 Author

thanks again for explanations 💚,

Collapse
codingsafari profile image
Nico Braun

There is a module for this, util.promisify. It probably will do it better than anyone could show you here.

const { promisify } = require('util')
const sleep = promisify(setTimeout)
Enter fullscreen mode Exit fullscreen mode
Collapse
bacloud14 profile image
bacloud14 Author

I will take a look on util.promisify thanks Nico !