Запрос обратного вызова с аргументами и синхронными запросами

У меня есть две проблемы при реализации службы RESTful с использованием Node.js / node-postgres lib / PostgreDB, и обе они связаны с асинхронной природой JS.

А) Мне нужно передать дополнительный аргумент обратному вызову в вызове client.query(query, callback)

Я нахожусь внутри обратного вызова запроса и просматриваю массив недавно извлеченных строк из БД и хочу запустить последующий запрос для каждого из них:

var query =  client.query('SELECT * FROM event', queryAllEventsHandler);
function queryAllEventsHandler(err, result){        
   allEvents = result.rows;

   /* allEvents is an JSON array with the following format
   [  {"id_event":1, "name":"name of the event"}, 
      {"id_event":1, "name":"name of the event"} 
   ]
   */

for(var i = 0; i<allEvents.length; i++){
     client.query('SELECT * FROM days where id_event = $1',[allEvents[i].id_event], function( err, result){
               //I want to have a reference to variable i
     }
}

В приведенном выше примере я хочу сделать что-то вроде:

client.query('SELECT * FROM days where id_event = $1',[allEvents[i].id_event], function( AN_EXTRA_ARG, err, result)

Где AN_EXTRA_ARG - это дополнительный аргумент или замыкание в функции обратного вызова... Как я могу этого добиться? Должен ли я создать замыкание с помощью i и передать его как аргумент обратного вызова? Как?:|

Б) "Синхронизация" запросов

Мне нужно запустить различные запросы и создать собственный JSON из всех них. Так как каждый запрос и его обратный вызов являются асинхронными (никого не ожидая), я искал способ "укротить" его, и среди прочего я нашел решение, которое сначала пришло мне в голову, но показалось немного "плохим / паршивым" Msgstr "Сохранение количества запросов - это действительно тот путь, который предлагает @jslatts в синхронных запросах к базе данных с Node.js?

Надеюсь я

4 ответа

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

Как вы знаете ключевое слово, оно соответствует объекту Window (top) внутри функции (если это не функция метода). Используя функцию связывания, вы можете изменить ссылку на свой собственный объект...

Итак, что я сделал, я создал именованную функцию queryCallback

function queryCallback(err, result){
        //this == Window (default)             
}

изменил анонимную функцию обратного вызова на именованный queryCallback:

client.query('SELECT * ... where id_event = $1',[allEvents[i].id_event], queryCallback.bind( {"position":i},  err, result));

Теперь обратите внимание на queryCallback.bind( {"position":i}, err, result));

Что делает привязка (my_custom_this, [другие аргументы]), так это связывает пользовательский объект (в моем случае {"position":i}) с этим внутри функции, для которой была вызвана привязка...

Теперь у нас есть такой сценарий:

function queryCallback(err, result){
            //this == {"position":i}
}

Бинд объяснил: http://fitzgeraldnick.com/weblog/26/

Что касается вопроса А, вы можете создать функцию, которая будет обрабатывать оба ваших запроса и возвращать их только при выполнении последнего запроса и возвращать оба результата в обратный вызов.

for(var i = 0; i<allEvents.length; i++){
  query(client, allEvents[i], function(result1, result2) {
    //do something
  });   
}

function query(client, event, callback) {
    client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err1, result1){
        client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err2, result2){
          callback(result1, result2);
        });
     });
}

Для B) ваши параметры включают асинхронность или библиотеку Promise (например, Q, when.js, Bluebird и т. Д.)

A) Мне лично нравится lodash (или подчеркивание, если вы предпочитаете) partial() за это. Он принимает функцию и ряд аргументов и возвращает функцию с примененными аргументами, а оставшиеся аргументы остаются открытыми. Это очень похоже на функциональную концепцию карри.

Б) Для объединения нескольких асинхронных результатов я настоятельно рекомендую асинхронный. Синтаксис займет некоторое время, чтобы привыкнуть, но делает такую ​​вещь очень простой. Быстрый образец:

async.parallel([
    one: function(callback){
        db.fetch(options, callback);
    },
    two: function(callback){
        db.fetch(options, callback);
    }
],
function(err, results){
    // this callback will get called when either parallel call gives an error
    // or when both have called the callback
    if (err) {
        // handle error
        return;
    }

    // get the results from results.one and results.two
});

== Добавлено в правку ==

На самом деле, lodash также предлагает более хорошее (imho), хотя и несколько более дорогое решение (из-за вызовов функций) для вашей проблемы A):

_(allEvents).each(function(event, index, array) {
    client.query('SELECT * FROM days where id_event = $1',[event.id_event], function( err, result) {
         // Just use 'index' here, which doesn't change during the each
     }
});
Другие вопросы по тегам