0

Есть следующий код:

app.get('/some', function(req, res) {
    var parm1 = parseFloat(req.query.parm1),
        parm2 = parseFloat(req.query.parm2),
        parm3 = parseFloat(req.query.parm3),
        parm4 = parseFloat(req.query.parm4);

    if (parm1 && parm2 && parm3 && parm4) {
        if (...) {
            res.json({ message: 'Some ok 1' });
        } else {
            ...
            var data = []; // Массив с тем, что будем выводить

            for(var i = 0; i < some1; i++) {
                ...
                for(var s = 0; s < some2; s++) {
                    Model.count({ ... }, function(err, count){
                        if(err) throw err;

                        if (count > 0) {
                            var d = {
                                ...
                                length: count
                            }

                            data.push(d); // Кладем в массив
                        }
                    });
                }
            }

            res.json({ message: 'Some ok 2', content: data }); // Выводим
        }
    } else {
        return res.status(403).send({ message: 'Some error' });
    }
});

Логика такова: получаем во вложенном цикле количество необходимых записей в БД и пишем данные в массив data, затем отдаем пользователю.

Видимо из-за асинхронности отдается пустой массив. Как сделать так, чтобы данные отдавались по завершении всех операций в циклах?

P.S. В условии выборки Model.count({ ... }) используются i и s из циклов.

posix
  • 359
  • 2
  • 21
  • Не "возможно", а так и есть: http://ru.stackoverflow.com/questions/554290/%d0%9a%d0%b0%d0%ba-%d0%b2%d0%b5%d1%80%d0%bd%d1%83%d1%82%d1%8c-%d0%b7%d0%bd%d0%b0%d1%87%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b8%d0%b7-%d1%81%d0%be%d0%b1%d1%8b%d1%82%d0%b8%d1%8f-%d0%b8%d0%bb%d0%b8-%d0%b8%d0%b7-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-%d0%be%d0%b1%d1%80%d0%b0%d1%82%d0%bd%d0%be%d0%b3%d0%be-%d0%b2%d1%8b%d0%b7%d0%be%d0%b2%d0%b0 – Pavel Mayorov Nov 04 '16 at 20:57
  • @PavelMayorov, не стоит ли закрыть дубликатом на этот вопрос? или на этот – Grundy Nov 04 '16 at 22:18
  • @Grundy тут рассматривается случай, применительно к конкретным инструментам: node.js и mongo. И как показала практика, общие решения тут не всегда подходят. – posix Nov 04 '16 at 22:50
  • @posix, в принципе, если можно из Model.count получить Promise - то общее решение вполне подойдет – Grundy Nov 04 '16 at 22:55
  • @Grundy, исходя из моих попыток - это не работает. Если у вас получится, буду счастлив увидеть пример. – posix Nov 05 '16 at 04:41
  • 1
    @posix лучше выложите код ваших попыток. Потому что все работает. – Pavel Mayorov Nov 05 '16 at 05:18
  • 1

1 Answers1

-1

Как вариант на колбеках:

app.get('/some', function(req, res) {
    var data = []; // Массив с тем, что будем выводить

    var firstLoop = function(i, some1, callback1){
        if(i < some1){
            ...
            var secondLoop = function(s, some2, callback2){
                if(s < some2){
                    Model.count({ ... }, function(err, count){
                        data.push(d);
                        secondLoop(s++, some2, callback2);
                    });
                }else{
                    callback2();
                }
            }

            secondLoop(0, some2, function(){
                firstLoop(i++, some1, callback1);
            });

        }else{
            callback1();
        }
    }

    firstLoop(0, some1, function(){
        res.json({ message: 'Some ok 2', content: data });
    });
});

Заменяем циклы рекурсивными функциями, которые вызывают самих себя, пока верно условие, и вызывают callback когда заканчивают циклы. Второй циклы ждет пока выполнится запрос, кладет данные в массив и выполняет следующую итерацию, как только закончит, запускает следующую итерацию первого цикла, как только закончен первый цикл, он отправляет ответ. Таким образом сначала выполнятся все запросы и циклы и затем выдаст ответ.

Так же реализуют с помощью promise, или библиотек, таких как async.

Bookin
  • 3,478
  • Приведенный пример намертво вешает ноду. Думаю стоит смотреть в сторону async, но там, как я понимаю, задается конкретное количество последовательных функций, а у меня это количество может быть разным. Если пускать циклы в одной функции - ничего не выходит. Если кто знает решение, буду благодарен за подсказку или намек. – posix Nov 04 '16 at 22:46
  • @posix, а какие значение some1 и some2 использовались? если просто вставить как есть они будут undefined и будут бесконечно в глубь уходить – Grundy Nov 05 '16 at 07:23
  • 1
    Пример на то и пример, что он просто пример. – Bookin Nov 05 '16 at 12:36