0

I use a function called setConf for testing. Sometimes it's really convenient if I can use it to start a promise chain, sometimes I just need need it to return the value.

Is it possible to declare an existing function as async? What I would like to do but it doesn't work is:

const setConf = (conf) => {
  mainConf = Object.assign(mainConf , conf)
  return mainConf 
}

module.exports.asyncSetConf = async setConf
module.exports.setConf = setConf

this I currently have

exports.asyncSetConf = async (conf) => {
  mainConf = Object.assign(mainConf , conf)
  return mainConf 
}

exports.setConf = (conf) => {
  mainConf = Object.assign(mainConf , conf)
  return mainConf 
}

The code is identical, It seems kinda silly not to be able to refactor this

lonewarrior556
  • 3,917
  • 2
  • 26
  • 55
  • 2
    There is no value in making a function that executes synchronously an async function. but, you very well could do so by creating a new function that calls that function on the next tick. – Kevin B Dec 20 '17 at 17:27
  • @KevinB I think it was just an example. I think the use-case for async is implied – mhodges Dec 20 '17 at 17:27
  • afaik you can't convert an existing function to an async function. but nothing is stopping you from creating a new function – Kevin B Dec 20 '17 at 17:29
  • *"Is it possible to declare an existing function as async?"* No. An async function is a function that returns a promise. If you you need a promise you could simply do `Promise.resolve(someExistingFunction())`. If you want to use `await`, you can already do that: `await someExistingFunction()` (no matter what `someExistingFunction` returns. – Felix Kling Dec 20 '17 at 17:29
  • You can't use the async keyword on the right hand of an assignment expression because that is not what the async keyword is for. It is for declarations, not assignment expressions. Syntactically this is why this is invalid. Now, if you were to say `module.exports.asyncSetConf = async (conf) => ...` that will work, because it is now being used as a part of a declaration. – mhodges Dec 20 '17 at 17:30
  • Adding the `async` keyword does not change how a function executes. If the function contained synchronous code, it will still execute that code synchronously even after making the function `async`. The three things that `async` changes are 1) it allows you to use `await` to await a promise inside the function and 2) it forces the function to return a promise that is resolved with whatever the return value is in the function, 3) it automatically catches some exceptions inside the function and makes them into a rejected returned promise. – jfriend00 Dec 20 '17 at 17:46
  • 2
    If you want to start a promise chain with it, then just do this: `Promise.resolve(setConf(...)).then(...)`. No need for an `async` version of it. – jfriend00 Dec 20 '17 at 17:49
  • [try avoiding async functions where possible](https://stackoverflow.com/a/45448272/1048572). – Bergi Dec 20 '17 at 17:57

1 Answers1

4

First off, a function declared with the async keyword returns a promise. So you either want your function to return a promise or you don't. There is no such thing as a function that is declared with the async keyword that sometimes returns a promise and sometimes doesn't.

Second off, if you have no asynchronous code in your function, then it's generally making things more complicated, not less complicated to wrap synchronous operations in an asynchronous interface, so there's generally no reason to do that.

Third off, if you just want to sometimes use setConf() to start a promise chain, you can simply wrap it with Promise.resolve() when you want to do that:

Promise.resolve(setConf(...)).then(f).then(g).catch(...)

Of course, you don't necessarily need to do that either because if f() is asynchronous and returns a promise, you could just do this:

f(setConfg(...)).then(g).catch(...)

If you find yourself using Promise.resolve(setConf(...)) a lot, then you can just make a utility function for it:

function setConfPromise(...args) {
    return Promise.resolve(setConf(..args))
}

Is it possible to declare an existing function as async?

You can change its declaration or you can wrap it with another function. You can't dynamically make it sometimes with async behavior and sometimes not. You need two separate functions for that.

You could wrap it like this:

module.exports.asyncSetConf = function(...args) {
    return Promise.resolve(setConf(...args));
}
module.exports.setConf = setConf

FYI, async should only be used when actually needed. Some notes about its usage:

  1. You should never use async when there no actual asynchronous code involved. Putting an asynchronous interface on synchronous code just makes use of the function more complicated than required.
  2. Use async when you want to use await inside the function.
  3. Use async when you to force automatically returning a promise and have some exceptions automatically caught and turned into a rejected promise.

Personally, I'd only ever use async when I want to use await inside the function.

You do not need to use async just to return a promise. You can do that the "old-fashioned" way by just returning a promise.

Using async does not make any synchronous code suddenly run asynchronously (a common newbie assumption). It doesn't change synchronous code at all. It forces the return value to be a promise which the caller has to use either await or .then() with to get the value from which will force a "next tick" execution on the .then(), but if the code in the function was all synchronous, it will still execute synchronously - async doesn't change that.

jfriend00
  • 683,504
  • 96
  • 985
  • 979