0

Result: a, b, d, c. Expected: a, b, c, d

 const promises = []
    console.log('a')
    someFunc(promises)
    Promise.allSettled(promises).then(() => console.log('d'))

    function someFunc(promises) {
      const promise = new Promise(resolve => setTimeout(() => {
        console.log('b')
        const promise2 = new Promise(resolve2 => setTimeout(() => {
          console.log('c')
          resolve2()
        }, 3000))
        promises.push(promise2)
        resolve()
      }, 3000))
      promises.push(promise)
      return promise
    }
Tran Chien
  • 614
  • 4
  • 10
  • Do not pass an array to be filled with promises into `someFunc`. Instead, make `someFunc` call `Promise.allSettled` itself. (And probably it doesn't even need to do that, it should just sequentially run the timeouts with `async`/`await` and return an array in the end). – Bergi May 10 '22 at 23:58
  • 1
    Can you show your real code, please? What are you trying to achieve? The current pattern makes no sense, and we can't advise a sensible alternative without knowing what you actually need. – Bergi May 10 '22 at 23:59
  • As you're new here, you may not realize that we can help faster and more accurately if you show real code that shows the actual problem you're trying to solve. Theoretical questions with pseudo-code are difficult to answer completely without teaching a whole chapter in a book. Questions that show real code with a real problem can be answered succinctly and accurately by just showing good code that solves and explains that specific problem. Please resist asking generic questions based on pseudo-code. – jfriend00 May 11 '22 at 00:02
  • Possible duplicate of [How to know when all Promises are Resolved in a dynamic "iterable" parameter?](https://stackoverflow.com/q/37801654/1048572) – Bergi May 11 '22 at 00:02
  • I don't have real code yet, it's an experiment. The idea is to supervise a JS function created via Function API, make sure all promises emitted by it to be done. So I created a `promises` array, wrap all method like `setTimeout`, `fetch` which auto push themself into the `promises` array. Then run the function and await that `promises` array. Tbh I'm very new here. – Tran Chien May 11 '22 at 00:10
  • Ok, but that still sounds like a bad idea. Promises are not "emitted". An asynchronous function is not meant to be "supervised", it is responsible itself for constructing and returning a (single) promise as its result. Or maybe you're looking for asynchronous iterators? – Bergi May 11 '22 at 00:15
  • The current webcontainer create an isolated environment for each individual source code to be executed in. My idea is to let them run directly on the browser. So that I can't let them access native browser api like `window`, `fetch`, `console` which mean I gotta wrap them and supervise the function. [inix](https://inix.pages.dev/). Imma try `async iterator`, this seem very like it. – Tran Chien May 11 '22 at 00:25
  • Please post your solution [as an answer](https://stackoverflow.com/help/self-answer), not as part of the question – Bergi May 11 '22 at 12:36

2 Answers2

0

While it'd be possible to patch it up by not pushing to an array, but instead having each Promise chain off of each other in someFunc...

console.log('a')
someFunc().then(() => console.log('d'))

function someFunc() {
  return new Promise(resolve => setTimeout(() => {
    console.log('b')
    new Promise(resolve2 => setTimeout(() => {
      console.log('c')
      resolve2()
    }, 3000))
      .then(resolve);
  }, 3000))
}

A much more understandable version would promisify setTimeout to begin with instead of doing it every time.

const setTimeoutPromise = ms => new Promise(resolve => setTimeout(resolve, ms));

console.log('a')
someFunc().then(() => console.log('d'))

function someFunc() {
  return setTimeoutPromise(3000)
    .then(() => {
      console.log('b');
      return setTimeoutPromise(3000)
    })
    .then(() => {
      console.log('c');
      return setTimeoutPromise(3000)
    });
}

Which can be further simplified with await...

const setTimeoutPromise = ms => new Promise(resolve => setTimeout(resolve, ms));

console.log('a')
someFunc().then(() => console.log('d'))

async function someFunc() {
  await setTimeoutPromise(3000);
  console.log('b');
  await setTimeoutPromise(3000);
  console.log('c');
  await setTimeoutPromise(3000);
}
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

Solution

I know you may be confused on this question a lot. Here is the solution I found

const promises = []
const timeout = ms => {
    const promise = new Promise(resolve => setTimeout(resolve, ms))
    promises.push(promise)
    return promise
}

const someFunc = () =>
    timeout(1000).then(() => {
        console.log('b')
        timeout(1000).then(() => console.log('c'))
    })

async function main() {
    console.log('a')
    someFunc()
    let i = 0;
    while (promises.length > i) {
        i = promises.length
        await Promise.allSettled(promises)
    }
    console.log('d')
}

main()

The problem I really want to express is that the content of the function someFunc is not determined at compile time while I need to make sure that the function leave no side effect once executed.

Tran Chien
  • 614
  • 4
  • 10