Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
389 views
in Technique[技术] by (71.8m points)

javascript - Can I use this implementation of Promise.allSettled before ES2020?

I am working with a broken codebase so I am trying to touch as little as possible. In particular, right now it's using TypeScript and ES6, and I need to launch an array of promises and wait for them all to finish before I move on with the code execution, regardless of if they resolve or reject. So this is the usecase for Promise.allSettled, which is only available in ES2020.

I tried the following implementation:

const myPromiseAllSettled = (promises) => new Promise((resolve, reject) => {
  const results = []
  const settle = (result) => {
    results.push(result)
    if (results.length === promises.length) {
      (results.every(value => value) ? resolve : reject)(promises)
    }
  }
  promises.forEach(promise => {
    promise
      .then(() => settle(true))
      .catch(() => settle(false))
  })
})

but I have only seen my own code when it comes to promises, so I would like to get some feedback on my implementation. Does it do what other developers would expect it to do? Especially when it comes to the arguments passed to resolve/reject; right now I only pass the array of promises and expect the developer to run a .then(promises => promises.forEach(...)) if they are interested in following up on the individual promises.

I also don't know ideally how I would handle the types with TypeScript here, since I am not so experienced with TypeScript as well. (Writing 'any' everywhere doesn't seem cool to me.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

it should look more like this:

const myPromiseAllSettled = (promises) => {
  const fulfilled = value => ({ status: "fulfilled", value });
  const rejected = reason => ({ status: "rejected", reason });

  return Promise.all([...promises].map(p => Promise.resolve(p).then(fulfilled, rejected)));
}

[...promises] to handle cases where promises is iterable but not an array. Promise.resolve(p) because the passed value may be not a Promise (or thenable).

If you simply want to be notified about the success, you can do something simpler:

const success = await Promise.all(promises).then(() => true, () => false);

Edit: Didn't like the way handled promises may be an iterable but no array. Adding a version that Array#maps over iterables:

function* map(iterable, callback) {
  for (const value of iterable) {
    yield callback(value);
  }
}

const myPromiseAllSettled = (promises) => {
  const fulfilled = value => ({ status: "fulfilled", value });
  const rejected = reason => ({ status: "rejected", reason });

  return Promise.all(
    map(
      promises,
      p => Promise.resolve(p).then(fulfilled, rejected)
    )
  );
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...