uneasy
uneasy

Reputation: 619

JavaScript Promises confusion anti-pattern?

I spent whole day trying to figure out weather I use Promises wrongly.

Is that anti-pattern ?

export const myExample = (payload) => {
  return new Promise((resolve, reject) => {})
}

Can I use async in promise like that ?

export const myExample = (payload) => {
  return new Promise(async (resolve, reject) => {})
}

Also is that wrong as well ? Assuming adding async makes it a promise by default,

export const myExample = async (payload) => {
  return new Promise((resolve, reject) => {})
}

also if that's the case, should I just return from function which will be same as resolve, and if I throw Error will be reject, so it would look like that ?

export const myExample = async (payload) => {
  if(payload) return true
  else throw new Error('Promise rejection?')
}

So is first and last the same ?

Upvotes: 7

Views: 443

Answers (4)

Eduard
Eduard

Reputation: 2148

It's a nice question, I was facing that kind of confusions as well and wanted to know where and what kind of structure to use. Came up with this:

async/await - I use it at a high level where mostly I write my handling part

async function asyncExample() {
  try {
    const sampleData = await otherFunction();
    // You code here
  } catch (err) {
    // Your error handling here
  }
}

It's always a good idea to use try/catch in async/await

Using new Promise(resolve, reject) concept. I mostly use it when I have to wrap a function that only supports callbacks.

function promiseExample() {
  return new Promise((resolve, reject) => {
    // your code to resolve()
    // otherwise to reject()
  });
}

But there is a nice module promisify which sometimes is a better solution then wrapping each function

Upvotes: 2

t.niese
t.niese

Reputation: 40852

export const myExample = (payload) => {
  return new Promise((resolve, reject) => {})
}

should only be used to convert code that is not promise based but returns the result asynchronously into a Promise.

export const myExample = (payload) => {
  return new Promise(async (resolve, reject) => {})
}

Is an anty pattern async already makes a function to return a Promise, and you break the promise chaining here.

export const myExample = async (payload) => {
  return new Promise((resolve, reject) => {})
}

Same as the first one new Promise should only be used to convert code that is not promise based but returns the result asynchronously into a Promise. If async can be committed depends on the other code within that function. But it would be better that if you need to use new Promise((resolve, reject) => {}) that the enclosing function only contains and returns that new Promise like in your first example.

also if that's the case, should I just return from function which will be same as resolve, and if I throw Error will be reject, so it would look like that ?

yes

Upvotes: 3

EugenSunic
EugenSunic

Reputation: 13703

It's not an anti pattern, you need to do some logic with your payload argument inside the promise using the resolve function, for instance resolve(payload+'concatenate') , also you should implement the reject function based on the payload argument presumably

 export const myExample = (payload) => {
      return new Promise((resolve, reject) => {})
    }

You should not be using async await once defining a promise, those are to be used upon calling/executing promises only.

export const myExample = (payload) => {
  return new Promise(async (resolve, reject) => {})
}

The same goes for this code snippet

export const myExample = async (payload) => {
  return new Promise((resolve, reject) => {})
}

you should use await within your function since you are using the async keyword, also there is no promises defined in the snippet so make sure you define them before using async await, hence you'll be able to return some value or throw an error

export const myExample = async (payload) => {
  if(payload) return true
  else throw new Error('Promise rejection?')
}

Upvotes: 0

Dan Starns
Dan Starns

Reputation: 3823

This is considered an 'anti-pattern' because there is a passability that errors can go uncaught. If an execution in the async function throws the error will be lost and won't cause the newly-constructed Promise to reject.

You can get around this problem by making sure you use try/catch although this necessary requirement can make your code more brittle.

How can I use this pattern correctly?

function promise() {
    return new Promise(async (resolve, reject) => {
        try {
            await iWillThrow() // throw err
        } catch (error) {
            reject(error) // need to reject here, error will not 'bubble'
        }
    });
}

How can this pattern catch me out?

function promise() {
    return new Promise(async (resolve, reject) => {
            await iWillThrow() // throw err, unhandled error ⚠
    });
}

I found the eslint explanation here usefull.

Upvotes: -1

Related Questions