HixField
HixField

Reputation: 3776

Avoid nesting promises

I'm getting an "Avoid nesting promises" (for jslint) for the following function. How can I write this without nesting promises?

function deleteUIDsFromDBForKey(rootkey, users_uids) {
  return retrieveUIDsFromDBForKey(rootkey)
    .then(uids => {
      let diff = uids.diff(users_uids)
      let deletes = []
      diff.forEach(key => {
        deletes.push(firebase.database().ref(rootkey + "/" + key).remove())
      })
      return Promise.all(deletes)
        .then(value => {
          return diff
        })
    })
}

Upvotes: 0

Views: 2182

Answers (2)

jfriend00
jfriend00

Reputation: 707158

I this case, I think jsLint is just steering you wrong into more complicated code. Sometimes, you get that from a linter and the best option in that case is to bypass the linter for a specific line of code or function or a specific linter rule.

This is the simplest and clearest implementation of your code I can think of (which should be your priority):

function deleteUIDsFromDBForKey(rootkey, users_uids) {
    return retrieveUIDsFromDBForKey(rootkey).then(uids => {
        const diff = uids.diff(users_uids);
        // wait for all deletes to be done, then return diff
        return Promise.all(diff.map(key => {
            return firebase.database().ref(rootkey + "/" + key).remove();
        })).then(() => diff);
    });
}

Or, using Bluebird's .map(), you can do this:

// using Bluebird's Promise.map()
function deleteUIDsFromDBForKey(rootkey, users_uids) {
    return retrieveUIDsFromDBForKey(rootkey).then(uids => {
        const diff = uids.diff(users_uids);
        // wait for all deletes to be done, then return diff
        return Promise.map(diff, key => {
            return firebase.database().ref(rootkey + "/" + key).remove();
        }).then(() => diff);
    });
}

Or, using async/await:

async function deleteUIDsFromDBForKey(rootkey, users_uids) {
    const uids = await retrieveUIDsFromDBForKey(rootkey);
    const diff = uids.diff(users_uids);
    await Promise.all(diff.map(key => {
        return firebase.database().ref(rootkey + "/" + key).remove();
    }));
    return diff;
}

I don't have an ES7-capable jsLint installed, but the last option should avoid the nesting warning. The first two, probably not, but trying to avoid that warning will just make worse code so IMO, you should just disable the warning.

Upvotes: 0

trincot
trincot

Reputation: 350079

The last then can be moved up to the main chain by returning the Promise.all result:

function deleteUIDsFromDBForKey(rootkey, users_uids) {
  let diff;
  return retrieveUIDsFromDBForKey(rootkey)
    .then(uids => {
      diff = uids.diff(users_uids)
      let deletes = []
      diff.forEach(key => {
        deletes.push(firebase.database().ref(rootkey + "/" + key).remove())
      })
      return Promise.all(deletes)
    })
    .then(value => {
      return diff
    })
}

Note that for this to work, the scope of the variable diff needs to be enlarged, as done above. Alternatively you could add diff to the arguments passed to Promise.all, so you get access to diff as a promised value:

function deleteUIDsFromDBForKey(rootkey, users_uids) {
  return retrieveUIDsFromDBForKey(rootkey)
    .then(uids => {
      let diff = uids.diff(users_uids)
      let deletes = []
      diff.forEach(key => {
        deletes.push(firebase.database().ref(rootkey + "/" + key).remove())
      })
      return Promise.all([diff, ...deletes])
    })
    .then(([diff]) => {
      return diff
    })
}

Unrelated to your question, but you could use map instead of forEach with push:

  let deletes = diff.map(key => {
    return firebase.database().ref(rootkey + "/" + key).remove()
  })

Upvotes: 3

Related Questions