Skip to main content
 首页 » 编程设计

javascript之如何顺序执行 Promise,从数组传递参数

2024年02月20日18lori

var myArray = [1, 2, 3, 4, 5, 6] 
 
function myPromise(num){ 
  return new Promise(res => { 
    window.setTimeout(()=>{ 
      res(  console.log("done: " + num)  ) 
    },2000) 
  }) 
} 
 
 
myPromise(myArray[0]) 
  .then(x => myPromise(myArray[1])) 
  .then(x => myPromise(myArray[2])) 
  .then(x => myPromise(myArray[3])) 
  .then(x => myPromise(myArray[4])) 
  .then(x => myPromise(myArray[5])) 

现在,如果我执行上面的语句,它将按顺序运行。在我的实际用例中,数组是动态填充的,我需要为 myArray 中的每个成员执行 myPromise() 函数。

如何制作一个“可暂停循环”,该循环将为数组中的每个项目循环,执行 myPromise 并等待 promise 得到解决,然后再继续下一次迭代?

请您参考如下方法:

如果您可以像问题中的情况那样创建与数组元素一样多的 Promise,则可以非常整齐地重复应用 .then :

myArray.reduce( 
  (p, x) => 
    p.then(() => myPromise(x)), 
  Promise.resolve() 
) 

但考虑到支持,异步函数是更好的选择。它具有良好的可读性,并且具有 O(1) 而不是 O(n) 的内存开销。

const forEachSeries = async (iterable, action) => { 
  for (const x of iterable) { 
    await action(x) 
  } 
} 
 
forEachSeries(myArray, myPromise) 

如果你想将返回值收集为数组,那就是:

const mapSeries = async (iterable, fn) => { 
  const results = [] 
 
  for (const x of iterable) { 
    results.push(await fn(x)) 
  } 
 
  return results 
} 

或者,没有异步函数支持,

const mapSeries = (iterable, fn) => { 
  const iterator = iterable[Symbol.iterator]() 
  const results = [] 
  const go = () => { 
    const {value, done} = iterator.next() 
 
    if (done) { 
      return results 
    } 
 
    return fn(value).then(mapped => { 
      results.push(mapped) 
      return go() 
    }) 
  } 
 
  return Promise.resolve().then(go) 
} 

可运行片段:

const myArray = [1, 2, 3, 4, 5, 6] 
 
const sleep = ms => 
  new Promise(res => { 
    setTimeout(res, ms) 
  }) 
 
const myPromise = num => 
  sleep(500).then(() => { 
    console.log('done: ' + num) 
  }) 
 
const forEachSeries = async (iterable, action) => { 
  for (const x of iterable) { 
    await action(x) 
  } 
} 
 
forEachSeries(myArray, myPromise) 
  .then(() => { 
    console.log('all done!') 
  })