Javascript 转换为嵌套承诺的嵌套For循环

Javascript 转换为嵌套承诺的嵌套For循环,javascript,promise,bluebird,Javascript,Promise,Bluebird,我遇到了一个问题,我的程序只在名称列表的一次迭代中结束,我不确定不合逻辑的代码在哪里 鉴于全球: var _ = require("underscore"); var nameList = ["Bob", "Susie"] var jsonDict = {} 我复杂的嵌套从这里开始,但我不确定如何修复它,以便它在名称列表和循环1-10的数字中迭代: return new Promise((res, rej) => { var promises = []; return P

我遇到了一个问题,我的程序只在
名称列表的一次迭代中结束,我不确定不合逻辑的代码在哪里

鉴于全球:

var _ = require("underscore");
var nameList = ["Bob", "Susie"]
var jsonDict = {}
我复杂的嵌套从这里开始,但我不确定如何修复它,以便它在
名称列表
和循环
1-10
的数字中迭代:

return new Promise((res, rej) => {
    var promises = [];
    return Promise.map(nameList, function(personName){
        for (var j=1; j<=10; j++){
            return promises.push(new Promise(function(resolve, reject) {
                params['page'] = j;

                console.log('PAGE ' + j + ' ' + personName)

                SOME_SEARCH_FX_THAT_RETURNS_A_PROMISE(params).then(function(data){
                    return Promise.map(data, function(item, index){
                        if (!_.has(jsonDict, item.key)){
                            jsonDict[item.key] = {
                                name: personName
                            }
                        }
                        return
                    }).then(function(){
                        console.log(jsonDict)
                        return resolve(true)
                    })

                }).catch(function(err){
                    console.log(err)
                    return reject(false)
                })
            }))
        }
    }).then(function(){
        return res(true)
    })
}).then(function(){
    console.log('Done with everything.')
})
我从来没有得到Susie的数据,我很早就回来了,但似乎不知道在哪里。对于问题所在(甚至重构)的任何帮助/指导都将不胜感激。提前谢谢

第一:你的代码根本上是有缺陷的 我之所以说根本缺陷是因为您似乎误解了
函数的工作原理

return Promise.map(nameList, function(personName){  <-- this function 
  for (var j=1; j<=10; j++){
    return promises.push(new Promise(function(resolve, reject) { <-- is returning HERE
这里的内部承诺映射是不必要的,您可以使用标准的
映射
,甚至是
for循环
,因为您实际上没有在这里映射任何东西

[重构1] 好的,让我们向上移动回调金字塔(或者向下移动?)。下一个

for (var j=1; j<=10; j++){
  return promises.push(new Promise(function(resolve, reject) {
    params['page'] = j;

    console.log('PAGE ' + j + ' ' + personName)

    //[Refactored 1]
  }))
}
我将快进,因为我注意到这已经变得很长了。重构的下一步

return new Promise((res, rej) => {
    var promises = [];
    return Promise.map(nameList, function(personName){
      //[Refactored 2]
    }).then(function(){
      return res(true)
    })
}).then(function(){
    console.log('Done with everything.')
})
我真的不知道如何挽救这一切,所以我会从小组里写一些东西

[重构3:最终版本]
好吧,仍然有这种不满意的感觉,但这就是我现在所拥有的。。。这对我来说比你更重要。再次感谢你,朋友。我希望我们双方都能继续推进这一不断变化的工作领域。如果所有这些听起来都是居高临下的话,我道歉。干杯

在这里,您还陷入了一个常见的陷阱:在循环变量上形成一个闭包,而不是它的值,这意味着您将多次处理页面
n
,并每隔一页忽略一次!“承诺是为了对抗回调地狱”——不是真的,承诺是为了给我们可返回的值,并且能够从异步回调中
返回
。我们仍然到处使用回调。为了对付它们,
async
/
await
被发明出来。感谢你给出了详尽的答案——感谢你的推理,我确实理解了为什么我的代码会提前结束。我仍在努力思考这个概念(以及如何更平稳地思考),你链接的文章非常有帮助——特别是看到我在新手错误部分的错误。我的代码经过一些调整后现在可以工作了。对其他读者/对我来说也很有帮助:
// Create subroutine, careful with the globals...
let populateJsonDict = singleData => {
  if (!_.has(jsonDict, singleData.key)) jsonDict[singleData.key] = { name: personName }
}

SOME_SEARCH_FX_THAT_RETURNS_A_PROMISE(params).then(data => {
    data.forEach(populateJsonDict);
    resolve(true); // this will be removed later
}).catch(function(err){
    console.log(err);
    reject(false); // this will be removed later
})
for (var j=1; j<=10; j++){
  return promises.push(new Promise(function(resolve, reject) {
    params['page'] = j;

    console.log('PAGE ' + j + ' ' + personName)

    //[Refactored 1]
  }))
}
for (var j=1; j<=10; j++){
  //[from Refactored 1]
  let populateJsonDict = singleData => {
    if (!_.has(jsonDict, singleData.key)) jsonDict[singleData.key] = { name: personName }
  }
  params['page'] = j; // I assume this a global somewhere
  let p = SOME_SEARCH_FX_THAT_RETURNS_A_PROMISE(params).then(data => {
    data.forEach(populateJsonDict);
    // Removed because we've removed the parent promise
  }).catch(function(err){
    console.log(err);
    // Removed because we've removed the parent promise
  })
  promises.push(p)
}
return new Promise((res, rej) => {
    var promises = [];
    return Promise.map(nameList, function(personName){
      //[Refactored 2]
    }).then(function(){
      return res(true)
    })
}).then(function(){
    console.log('Done with everything.')
})
var promises = [];
nameList.forEach(personName => { // Like earlier, redundant Promise.map
  //[from Refactored 2]
  for (var j=1; j<=10; j++){
    let populateJsonDict = singleData => {
        if (!_.has(jsonDict, singleData.key)) jsonDict[singleData.key] = { name: personName }
    }
    params['page'] = j;
    let p = SOME_SEARCH_FX_THAT_RETURNS_A_PROMISE(params).then(data => {
        data.forEach(populateJsonDict);
    }).catch(function(err){
        console.log(err);
    })
    promises.push(p)
  }
});
// At this point you have an array of Promises, for this we can utilize Promise.all

Promise.all(promises)
    .then(() => console.log('Done with Everything'));
let populateJsonDict = name => key => !_.has(jsonDict, key) && Object.assign(jsonDict, {[key]:name};
let promises = _.times(10, 
    index => {
        params['page'] = index+1;
        return Promise.map(nameList, name => {
            let populateWithName = populateJsonDict(name);
            let iterate = data => data.forEach(populateWithName);
            return SOME_SEARCH_FX_THAT_RETURNS_A_PROMISE(params)
                .then(iterate)
                .catch(err => console.log(err));
        });
    });

Promise.all(promises)
    .then(() => console.log('Everything done'));