简体   繁体   中英

blocking async functions in js?

I have a builder for long running async operations, and I need every one of those operation to run blocking, there should be only single task running at any moment.

In the code example, I want test to wait until all of it's internal awaits are resolved and only then resolve test function itself, allowing the code to continue with the next task.

;(async () => {

  const after = (time) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
  }

  const test = async (item) => {
    console.log("running item", item)
    await after(100)
    console.log("running step 1 item", item)
    await after(100)
    console.log("running step 2 item", item)
    await after(100)
    console.log("running step 3 item", item)
    await after(100)
    console.log("running step 4 item", item)
  }
  
  console.log("running")
  const promises = [1,2,3,4,5].map((item) => {
    return () => {
      test(item)
    }
  })
  for (const promise of promises) {
    console.log('running promise', promise)
    await promise()
  }

})()

At the moment, this code gives me an exception UnhandledPromiseRejectionWarning: TypeError: promise is not a function and also runs all test functions kind of in parallel, when every await call allows another test task to be run. Which is according to specifications, but not what I need.

Here is the output at the moment, showing that execution iterates over items, while I want item 1 to be fully processed before item 2

running
running item 1
running item 2
running item 3
running item 4
running item 5
running step 1 item 1
running step 1 item 2
running step 1 item 3
running step 1 item 4
running step 1 item 5
running step 2 item 1
running step 2 item 2
running step 2 item 3
running step 2 item 4
running step 2 item 5
running step 3 item 1
running step 3 item 2
running step 3 item 3
running step 3 item 4
running step 3 item 5
running step 4 item 1
running step 4 item 2
running step 4 item 3
running step 4 item 4
running step 4 item 5

SOLUTION: The key is not to create all promises but rather wait for each one to finish before creating the next one. Code, that works:

;(async () => {
  const after = (time) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
  }

  const test = async (item) => {
    console.log("running item", item)
    await after(100)
    console.log("running step 1 item", item)
    await after(100)
    console.log("running step 2 item", item)
    await after(100)
    console.log("running step 3 item", item)
    await after(100)
    console.log("running step 4 item", item)
  }

  console.log("running")
  const promises = [1, 2, 3, 4, 5].map((item) => {
    return async () => {
      await test(item)
    }
  })
  for (const promise of promises) {
    await promise()
  }
})()

Currently you're constructing all promises in one go. You'll want to only construct one promise when the previous one is done:

for (let i = 1; i <= 5; i++) {
    await test(i);
}

Alternatively you can construct a promise chain:

const p = [1, 2, 3, 4, 5].reduce((p, i) => p.then(() => test(i)), Promise.resolve())
await p;

This is equivalent to:

const p = test(1).then(() => test(2)).then(...);

I have a builder for long running async operations, and I need every one of those operation to run blocking, there should be only single task running at any moment.

In the code example, I want test to wait until all of it's internal awaits are resolved and only then resolve test function itself, allowing the code to continue with the next task.

;(async () => {

  const after = (time) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
  }

  const test = async (item) => {
    console.log("running item", item)
    await after(100)
    console.log("running step 1 item", item)
    await after(100)
    console.log("running step 2 item", item)
    await after(100)
    console.log("running step 3 item", item)
    await after(100)
    console.log("running step 4 item", item)
  }
  
  console.log("running")
  const promises = [1,2,3,4,5].map((item) => {
    return () => {
      test(item)
    }
  })
  for (const promise of promises) {
    console.log('running promise', promise)
    await promise()
  }

})()

At the moment, this code gives me an exception UnhandledPromiseRejectionWarning: TypeError: promise is not a function and also runs all test functions kind of in parallel, when every await call allows another test task to be run. Which is according to specifications, but not what I need.

Here is the output at the moment, showing that execution iterates over items, while I want item 1 to be fully processed before item 2

running
running item 1
running item 2
running item 3
running item 4
running item 5
running step 1 item 1
running step 1 item 2
running step 1 item 3
running step 1 item 4
running step 1 item 5
running step 2 item 1
running step 2 item 2
running step 2 item 3
running step 2 item 4
running step 2 item 5
running step 3 item 1
running step 3 item 2
running step 3 item 3
running step 3 item 4
running step 3 item 5
running step 4 item 1
running step 4 item 2
running step 4 item 3
running step 4 item 4
running step 4 item 5

SOLUTION: The key is not to create all promises but rather wait for each one to finish before creating the next one. Code, that works:

;(async () => {
  const after = (time) => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve()
      }, time)
    })
  }

  const test = async (item) => {
    console.log("running item", item)
    await after(100)
    console.log("running step 1 item", item)
    await after(100)
    console.log("running step 2 item", item)
    await after(100)
    console.log("running step 3 item", item)
    await after(100)
    console.log("running step 4 item", item)
  }

  console.log("running")
  const promises = [1, 2, 3, 4, 5].map((item) => {
    return async () => {
      await test(item)
    }
  })
  for (const promise of promises) {
    await promise()
  }
})()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM