What is the best way to wrap synchronous functions in to a promise

28,788

Solution 1

It is unclear why you would wrap a synchronous operation in a promise as that just makes it more difficult to use and synchronous operations can already be used within promise chains just fine.

The only two places I've seen it useful to make a promise out of something synchronous are to start a promise chain where subsequent operations will be async or when you are branching and one result of the branch is async promise and the other is synchronous. Then, in that case, you want to just return a promise in both cases so the caller has a consistent async interface no matter which branch is taken. Or, this could also occur with different implementations of a common API, one implementation which is synchronous and the other asynchronous. The API would be designed with an asynchronous interface and the synchronous implementation would probably wrap itself in a promise to fulfill the asynchronous contract of the common API.

Other than that, you should generally not make synchronous things async because it just unnecessarily complicates using them.

The simplest way I know of to make it into a promise would be this:

Promise.resolve(path.join(path1, path2)).then(function(path) {
   // use the result here
});

Per your comments, inside a .then() handler, exceptions are already captured by the promise infrastructure and turned into a rejected promise. So, if you had this:

someAsyncOp().then(function(value) {
   // some other stuff
   // something that causes an exception
   throw new Error("timeout");
}).catch(function(err){
   console.log(err);   // will show timeout
});

Then, that exception is already mapped into a promise rejection for you. Of course, if you want to handle the exception inside of the .then() handler (not turn the promise into a rejection), then you can just use a traditional try/catch around your synchronous operation to catch a local exception (no different than any other synchronous code). But, if you want the promise to reject if there's an exception inside the .then() handler, then that is all done for you automatically (a very nice feature of promises).

Solution 2

Not sure if it's the best way but it works. I came to StackOverflow to check if there's a better way.

new Promise((resolve, reject) => {
    try {
        resolve(path.join());
    } catch (err) {
        reject(err);
    }
})

Solution 3

Very quick way is to wrap prepend a function with async keyword. Any async function returns a Promise

const sum = async (a, b) => a + b;

sum(1, 2).then(value => console.log(value))
Share:
28,788
s1n7ax
Author by

s1n7ax

Updated on October 16, 2021

Comments

  • s1n7ax
    s1n7ax over 2 years

    Let's say I have a synchronous function like path.join(). I want to wrap it into a Promise because I want exceptions to be handled within catch() block. If I wrap it like below, I do not get an exception in the Promise's .catch() block. So I have to use if to check the return value for whether it's an error or not and then call resolve or reject functions. Are there any other solutions?

    var joinPaths = function(path1,path2) {
      return new promise(function (resolve, reject) {
        resolve(path.join(path1, path2));
      });
    };
    
    • Rodrigo Juarez
      Rodrigo Juarez almost 8 years
      Why do you want to wrap a synchronous function into a promise?
    • Alexei Levenkov
      Alexei Levenkov almost 8 years
      Unit testing is a common case when one needs to replace some async call with hard coded value
    • Bergi
      Bergi almost 8 years
      The best way to wrap a synchronous function into a promise is not to do it.
    • Bergi
      Bergi almost 8 years
      @Srinesh: Then use Promise.resolve().then(()=> path.join(path1, path2)).…
    • s1n7ax
      s1n7ax almost 8 years
      @RodrigoJuarez if im using path.join inside a then(), so i can manage all exceptions in a catch block
  • s1n7ax
    s1n7ax almost 8 years
    If i'm using path.join in promise chain and i want to handle exceptions in promise's .catch() block, how can i do that with out wrapping it in to a promise?
  • jfriend00
    jfriend00 almost 8 years
    @Srinesh - As always, if you put your actual code and actual problem into your question, we can help you much better. I don't follow exactly what you're trying to do. A .then() handler in a promise chain is already wrapped in a try/catch and any exception thrown in a .then() handler will reject the promise chain automatically. You don't have to do anything to get that functionality inside a .then() handler. You can also use try/catch yourself to catch a synchronous exception and handle it locally.
  • Daniel T.
    Daniel T. almost 7 years
    One reason why you might want to wrap a synchronous function in a promise is if you're trying to stick to a contract, i.e. if (needsUpdating) { return object.asyncUpdate(); } else { return object }; If one path returns a Promise, then so should the other path, even if it doesn't run any async code.
  • ckot
    ckot about 4 years
    I think this is along the same lines as @DanielT. mentioned, but I'm thinking it could be useful for creating an API which allows you to swap in different vendor implementations. I'm currently making a demo version of an app, where the real app uses Firestore, but I'll be using localStorage in the demo version. Even though localStorage is syncronous, I'd like to wrap with promises to make things transparent. Does this sound like a bad idea?
  • jfriend00
    jfriend00 about 4 years
    @ckot - Yes, an API that will sometimes be asynchronous, must always offer an asynchronous API even if, in some cases, the implementation is not asynchronous. That would be a valid/useful reason to wrap some synchronous code in a promise.
  • ckot
    ckot about 4 years
    @jfriend00 thx. glad to know I'm not introducing code smell by doing that.