2017-01-05 2 views
2

Я использую паруса (0.11.0), работающие на nodejs (6.9.1). Я пытаюсь построить массив, заполнив его для цикла. Я отправил бы этот завершенный массив в ответ на клиент. Я пробовал различные методы, как это было предложено людей здесь на переполнение стека, напримерПостроить массив в nodejs through для цикла

обсуждение here предложил

for (var i = yearStart; i < yearEnd+1; i++) { 
    arr.push(i); 
} 

На this обсуждения, предлагается использовать:

var array = calendars.map(function(item) { 
    return item.id; 
}); 

console.log(array); 

Точно так же я попробовал много методов, но я сталкиваюсь с той же проблемой, что во время цикла массив заполняется, но как только цикл завершается, массив становится пустым из-за асинхронного процесса, и поэтому я не могу отправить re sponse. Чтобы справиться с этим, я попытался проверить индекс внутри тела цикла и отправить отклик внутри тела цикла самого через

var userArray = []; 
_.each(users, function(user, index){ 
    MySQLConnector.query('CALL user_image (?)', [user.id], function(err, userImage){ 
    if(err){ 
     return res.json({"status":"some_error"}); 
    }else{ 
     userID = user.id 
     userImageID = userImage[0][0].id; 
     var userInfo = { 
     userID: userID, 
     userImageID: userImageID 
     } 
     userArray.push(userInfo) 
     if(index == users.length - 1){ 
      res.json({selectedUsers: userArray}); 
     } 
    } 
    }); 
}); 

Я начала пустой userArray, а затем перебрать пользователей объекта, где каждый элемент объект характеризуется именем пользователем и индекс. Через запрос MySQL я выборка объекта userImage и в каждой итерации, я создаю объект под названием USERINFO, который состоит из и идентификатора пользователя userImageID. Я нажимаю этот объект на userArray. И после каждой итерации цикла for (_.each), я проверяю, достигнут ли последний индекс. Как только последний индекс достигнут, последний массив отправляется как ответ до завершения цикла.

Здесь также возникает проблема, что тело массива не всегда полностью заполнено. Причина связана с асинхронным процессом, индекс не всегда соответствует порядку 0,1,2,3,4, .... и он может начинаться с любого числа и может перейти к любому индексу на следующей итерации, например, первый индекс для начала будет 4, второй будет 0, третий - 2 и так далее. Эта последовательность будет различной для каждого запуска этого цикла for. Для пользователя это будет полный случайный процесс. Поэтому, если users.length равен 8, и текущий индекс случайным образом 7 на третьей итерации, условие index == users.length - 1 будут выполнены и ответ будет послан только с массивом, состоящий из 3-х элементов, а не 8.

Может кто-то предложить мне нужен лучший и надежный способ заполнить массив через цикл for в nodejs и отправить этот массив в ответ, чтобы все элементы были включены в массив в исходном порядке?

+0

Он не будет следовать порядку, и я думаю, что у вас будет такая же проблема с картой. Посмотрите на сокращение в lodash и bluebird, я знаю, что в последнем он будет гарантировать порядок, я думаю, что lodash будет таким же, но может быть ошибочным в этом. –

+0

Думая об этом немного больше, в асинхронной библиотеке я часто использую everySeries, это тоже гарантирует заказ и, скорее всего, будет решением для вашего существующего кода. –

ответ

2

Поскольку вы используете узел js, лучше использовать любую библиотеку обещаний, такую ​​как bluebird или async для обработки запросов Async. Причина, по которой ваша петля не работает должным образом, заключается в том, что, как вы указали, из-за асинхронных запросов требуется время для решения, для которых цикл _.each не ждет.

Использование bluebird, это может быть сделано с Promise.map метод, который работает, как описано ниже от documentaion:

Учитывая итератора (массивы Iterable), или обещание итератора, который производит обещания (или сочетание обещаний и значений), перечислите по всем значениям в Iterable в массив и сопоставьте массив с другим, используя данную функцию сопоставления.

Ожидания, возвращаемые функцией картографа, ожидаются, и возвращенное обещание не выполняется до тех пор, пока не будут выполнены все сопоставленные обещания . Если какое-либо обещание в массиве отклонено или любое обещание , возвращенное функцией mapper, отклонено, то также возвращается отклоненное обещание .

Таким образом, используя Promise.map код может быть обновлен, как показано ниже:

var Promise = require("bluebird");  

return Promise.map(users, function(user, index){ 
    return MySQLConnector.query('CALL user_image (?)', [user.id], function(err, userImage){ 
    if(err){ 
     return Promise.reject({"status":"some_error"}); 
    }else{ 
     userID = user.id 
     userImageID = userImage[0][0].id; 
     var userInfo = { 
     userID: userID, 
     userImageID: userImageID 
     } 
     return userInfo; 
    } 
    }); 
}) 
.then(function (usersArray){ 
    res.json({selectedUsers: usersArray}); 
}) 
.catch(function (err){ 
    res.json(err); 
}); 
+0

Спасибо, собираюсь попробовать библиотеку обещаний. – harshvardhan

+0

Все еще я получаю массив ответов как '[null, null, null, null, null, null]' – harshvardhan

+0

Он должен работать, возможно, ответ, который вы получаете, равен null. Можете ли вы поместить журнал перед возвратом 'userInfo' в обратном вызове и проверить один раз. – superUser

1

Вы можете выполнить петли с функциями с обратными вызовами синхронно с использованием SynJS:

var SynJS = require('synjs'); 
var mysql  = require('mysql'); 
var connection = mysql.createConnection({ 
    host  : 'localhost', 
    user  : 'tracker', 
    password : 'tracker123', 
    database : 'tracker' 
}); 


function myFunction1(modules,connection,users) { 
    var ret=[]; 
    for(var i=0; i<users.length; i++) { 
     connection.query("SELECT CONCAT('some image of user #',?) AS userImage", [users[i]], function(err, rows, fields) { 
       if (err) throw err; 

       ret.push({ 
        id: users[i], 
        image: rows[0].userImage 
       }); 
       modules.SynJS.resume(_synjsContext); // <-- indicate that callback is finished 
     }); 
     SynJS.wait(); // <-- wait for callback to finish 
    } 
    return ret; 
}; 

var modules = { 
     SynJS: SynJS, 
     mysql: mysql, 
}; 

var users = [1,5,7,9,20,21]; 

SynJS.run(myFunction1,null,modules,connection,users,function (ret) { 
    console.log('done. result is:'); 
    console.log(ret); 
}); 

Результат будет следующим:

done. result is: 
[ { id: 1, image: 'some image of user #1' }, 
    { id: 5, image: 'some image of user #5' }, 
    { id: 7, image: 'some image of user #7' }, 
    { id: 9, image: 'some image of user #9' }, 
    { id: 20, image: 'some image of user #20' }, 
    { id: 21, image: 'some image of user #21' } ] 
Смежные вопросы