2016-12-01 173 views
0

我有3个总的forEach循环,我希望前两个等待承诺的然后块执行之前,他们重新开始和迭代。我已经用console.log语句证明了这一点,分别标记为1,2和3.如何在循环再次迭代之前等待承诺的“then”块在嵌套的forEach循环中执行?

我想要控制台日志按顺序排列,如“1,2,3,1,2,3等” 而是我得到的是“1,2,1,2,1,2,1,2,1,2,3,3,3,3,3,3” 我如何使这一切顺序? fetchCandidatesByCity是mongoose find方法,它返回一个promise。

axios.get(FEED_URL).then(data => { 
let candidatesWithMessageSent = []; 

data.data.jobs.forEach(job => { 
    console.log("1"); 
    // console.log(candidatesWithMessageSent); 
    job.city.forEach(cityAndState => { 
    console.log("2"); 

    let jobState = extractState(cityAndState); 

    let jobLocation = addSpaceAfterComma(cityAndState.toLowerCase()); 

    let jobCity = extractCity(jobLocation); 


    fetchCandidatesByCity(jobCity) 
     .then(candidates => { 
     candidates.forEach((candidate, index) => { 
      console.log("3"); 
      const candidateId = candidate._id.toString(); 

      if (index <= MAX_MESSAGE_LIMIT && 
      !containsUberLyft(job.title) && 
      priceIsHigh(job.price) && 
      !candidateHasMessage(candidatesWithMessageSent, candidateId)) { 

      const jobURL = `http://www.jobs2careers.com/click.php?id=${job.id}.${PUBLISHER_ID}`; 

      // candidate has received a job notification, so add candidate to candidatesWithMessageSent 

      candidatesWithMessageSent = [ ...candidatesWithMessageSent, candidateId ]; 

      } 
      return; 
     }); 
     }) 
     .catch((error) => { 
     console.log(error); 
     }); 
    }); 
}); 

});

+2

您的示例代码从不使用'data'和'pieceOfData'。这是否代表您询问的实际情况,还是实际使用它们?如果是后者,你需要展示他们将如何使用。 – cybersam

+0

该函数本身很长,但我可以展示它。此示例代码是缩写版本。 – Mjuice

+0

你想要处理所有异步操作的结果是确定哪种解决方案效果最好的重要组成部分,因此我们需要更多关于循环和你想要做什么的细节。 – jfriend00

回答

0

let seq = Promise.resolve() 
 
let myData = [[1.1,1.2],[2.1,2.2]]; 
 
function findUser() { 
 
    return new Promise(resolve => { 
 
     setTimeout(() => { 
 
      resolve(['a','b']); 
 
     }, 500); 
 
    }); 
 
} 
 
myData.forEach(data => { 
 
    seq = seq.then(() => { // chain myData.forEach 
 
     console.log(data); 
 
     let seq = Promise.resolve(); 
 
     data.forEach(data => { 
 
      seq = seq.then(() => { // chain data.forEach 
 
       console.log(data); 
 
       return findUser({}).then(users => { 
 
        users.forEach(user => { 
 
         console.log(data, user); 
 
        }) 
 
       }) 
 
      }) 
 
     }) 
 
     return seq; 
 
    }); 
 
});

7

一种常见的设计模式来迭代串联使用异步操作是使用.reduce()其中你积累一个承诺的阵列。概括而言,其工作原理如下:

array.reduce(function(p, item) { 
    return p.then(function() { 
     return someAsyncPromise(item); 
    }); 
}, Promise.resolve()).then(function(finalValue) { 
    // all done here 
}).catch(function(err) { 
    // error here 
}); 

Promise.resolve()作为累加器的初始值被传入。循环的每次迭代都会执行return p.then(someOperation)

这基本上链一大堆操作起来是这样的:

Promise.resolve().then(...).then(...).then(...).then(...).then(...) 

如果每个自定义功能由.then()处理函数调用的时候,它是通过数组的下一个迭代值,并返回一个承诺将在下次调用f之前等待。


既然你有两个嵌套数组迭代循环,可以嵌套在另一个内部是这样的:

myData.reduce(function(p, nestedArray) { 
    return p.then(function() { 
     return nestedArray.reduce(function(p2, item) { 
      return p2.then(function() { 
       return someAsyncPromise(item); 
      }); 
     }, Promise.resolve()); 
    }); 
}, Promise.resolve()).then(function(finalVal) { 
    // all done here 
}).catch(function(err) { 
    // error here 
}); 

或者,如果你不使用现有迭代的承诺解决的结果外reduce(),您可以简化有点像这样:

myData.reduce(function(p, nestedArray) { 
    return nestedArray.reduce(function(p2, item) { 
     return p2.then(function() { 
      return someAsyncPromise(item); 
     }); 
    }, p); 
}, Promise.resolve()).then(function(finalVal) { 
    // all done here 
}).catch(function(err) { 
    // error here 
}); 

这是AP蕾丝在Bluebird promise library使事情变得更容易,因为你可以使用Promise.mapSeries()迭代串联阵列和积累的结果数组:

Promise.mapSeries(myData, function(nestedArray) { 
    return Promise.mapSeries(nestedArray, function(item) { 
     return someAsyncPromise(item); 
    }); 
}).then(function(results) { 
    // all done here 
}).catch(function(err) { 
    // error here 
}); 

在所有这些情况下,您可以积累最终结果在一个对象成为最终承诺的解决价值,或者您可以将其用于副作用,其中您在更高范围内定义了一些其他对象,并且您在完成时使用该对象。

+0

如果你嵌套这些东西和内部数组不依赖于以前的结果,你可以简化内部'返回p.then(函数(){返回nestedArray.reduce(...,Promise.resolve()) ;})'返回nestedArray.reduce(...,p);' – Bergi

+0

@Bergi - 我添加了这个选项。 – jfriend00