Узел ждет весь асинхронный вызов перед выполнением кода - PullRequest
1 голос
/ 16 октября 2019

Я борюсь в течение нескольких дней за довольно простую проблему, я думаю.

У меня есть несколько вызовов, как это

for(var i = 1; i <= timeToIterate;i++){
    xapi.fetch({})
        .then(function (response) {
            response.results.forEach(y => {
                yapi.fetch({})
                    .then(function (response2){
                        //some treatment here with
                        response.articles.forEach(article => {
                            finalArray.push({})
                        });
                    })
        });
}

Нет проблем, пока все работает нормально, но теперь я хочу выполнитькод с моим finalArray после того, как все закончено. но когда я попытался поставить затем после второй, но она не выполняется должным образом, я попытался поставить после цикла for, но все еще пустой. Я даже пытался с некоторым ожиданием, но я не могу понять, как выполнить код, когда все тогда закончено.

Заранее спасибо.

РЕДАКТИРОВАТЬ: больше теста с ответом

var count = 0; //just to know how many articles
var completeArray = [];
var promise_arr = [];
xapi.fetch({})
    .then(async function (responseJson) {
        var timeToIterate = Math.ceil(responseJson.totalResultNumber / 50);
        for(var i = 1; i <= timeToIterate;i++){
            p = yapi.fetch({})
                .then(function (responseJson) {
                    if (responseJson.results.length > 0){
                            responseJson.results.forEach(x => {
                                zapi.fetch({})
                                    .then(function (response) {                            
                  response.articles.forEach(article =>{
                                         count++;
                                         console.log(count);
                                         completeArray.push({article};

                                     });

                                }).catch(e => {
                                    console.log(e);
                                 })
                            });
                        }
                    }).catch(e => {
                        console.log(e);
                     })
                     promise_arr.push(p);
                }
                await (Promise.all(promise_arr));
                console.log('now '+ completeArray.length);
                const  insert = elasticClient.bulk(
                    {body: completeArray},function (err, resp) {
                        completeArray = [];
                        if(resp.errors) {                                   
                            console.log(JSON.stringify(resp, null, '\t'));
                        }
                    });
            }).catch(e => {
                console.log(e);
             }).then(function(){
                return res.json(count);
            })

Но он все еще срабатывает до окончания функции for. Я что-то пропустил ? Я попытаюсь со вторым ответом!

РЕДАКТИРОВАТЬ 2: Я пробовал второй ответ тоже, но не могу найти, как заставить это работать без ошибки, я новичок с синей птицей, не знал это прежде сегодня

var count = 0;
var completeArray = [];
let response0 = await api1.fetch({});

await Promise.map(response0.results, async z => {
    console.log(z); //Good log here
    var timeToIterate = Math.ceil(z.totalResultNumber / 50);
                for (var i = 1; i <= timeToIterate; i++) {
                    let response = await api2.fetch({});

                    await Promise.map(response.results, async x => {
                        console.log(x) // No Log here
                        let response2 = await api3.fetch({});

                        await Promise.map(response2, y => {
                            if (y.sections && y.sections.length > 0) {
                                y.sections.forEach(section => {
                                    if (section.articles.length > 0) {                                    
                                        lawSection.articles.forEach(article => {
                                            count++;
                                            console.log(count);
                                            completeArray.push(article)
                                        });
                                    }
                                })
                            } else if (y.articles && y.articles.length > 0) {
                                y.articles.forEach(article => {
                                    count++;
                                    console.log(count);
                                    completeArray.push(article);
                                });
                            }
                        });
                    });
                }
                console.log('now ' + completeArray.length); // got this log Z time but nothing above so completeArray.length always = 0
                const insert = elasticClient.bulk({
                    body: completeArray
                }, function (err, resp) {
                    completeArray = [];
                    if (resp.errors) {
                        console.log(JSON.stringify(resp, null, '\t'));
                    }
                });
            });

РЕДАКТИРОВАТЬ 3: Благодаря @tadman я понял это, но все еще есть проблема асинхронности для моего эластичного клиента, вот мой код

var count = 0;
var completeArray = [];
let response0 = await api1.fetch({});
    await Promise.map(response0.results, async z => {
        var timeToIterate = Math.ceil(response0.totalResultNumber / 50);
            for (var i = 1; i <= timeToIterate; i++) {
                let response = await api2.fetch({});
                await Promise.map(response.results, async x => {
                    if(response2.sections && response2.sections.length > 0){
                        response2.sections.forEach(section => {
                            if (section.articles.length > 0) {
                                section.articles.forEach(article => {
                                    count++;
                                    console.log(count);
                                    completeArray.push(article);
                                });
                            }
                        })
                    } else if (response2.articles && response2.articles.length > 0) {
                        response2.articles.forEach(article => {
                            count++;
                            console.log(count);
                            completeArray.push(article)
                        });
                    }
                });
                // I have to put it here because if i put it after the for loop the request http is to big and i have a 413 response. But the problem here is it didn't wait for the callback for the next 'for' loop iteration ! So i have the right number with my 'count' variable but didn't have the right number in my database 
                console.log('now ' + completeArray.length);
                await elasticClient.bulk( //how can i wait for the end of this and apply the completeArray = [] before the next iteration ?
                    {refresh: "wait_for",body: completeArray},
                    async function(err, response) {
                        completeArray = [];
                    if (err) { console.log(err); return; }
                    console.log(`Inside bulk3...`);
                    let errorCount = 0;
                    response.items.forEach(item => {
                        if (item.index && item.index.error) {
                        console.log(++errorCount, item.index.error);
                        }
                    });
                    console.log(`Successfully indexed items`);
                    }
                )
            }
        });

Ответы [ 2 ]

0 голосов
/ 16 октября 2019

Вы можете достичь этого, используя встроенное обещание, выполнив комбинацию map и введя результаты в Promise.all, который выглядит примерно так:

for(var i = 1; i <= timeToIterate;i++) {
  xapi.fetch({ })
    .then(response => {
      Promise.all(
        response.results.map(y => {
          return yapi.fetch({ })
            .then(response2 => {
                //some treatment here with
                response.articles.forEach(article => {
                  finalArray.push({ })
                });
              })
        })
      );
    });
}

Thisбыло бы проще, если бы вы разбили вещи на функции, так как здесь происходит множество вложений. Если вы можете использовать async / await, это также значительно упростит вещи.

Bluebird имеет Promise.map, что намного проще, поскольку объединяет эти два шага в один.

Комбинируя Bluebird и await, вы получаете что-то более читабельное, например:

for (var i = 1; i <= timeToIterate;i++) {
  let response = await xapi.fetch({ });

  await Promise.map(response.result, y => {
    let response2 = await yapi.fetch({ });

    response.articles.forEach(article => {
      finalArray.push({ })
    });
  });
}
0 голосов
/ 16 октября 2019

Я думаю, что вы спрашиваете: «Как мне дождаться завершения всех асинхронных вызовов, прежде чем что-то делать». Ответ заключается в использовании обещания и сохранении ваших обещаний в массиве. Как то так

promise_arr = []
for(var i = 1; i <= timeToIterate;i++){
    p = xapi.fetch({})
        .then(function (response) {
            response.results.forEach(y => {
                yapi.fetch({})
                    .then(function (response2){
                        //some treatment here with
                        response.articles.forEach(article => {
                            finalArray.push({})
                        });
                    })
        });
        promise_arr.push(p)
}
await(Promise.all(promise_arr))
//your code here
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...