Я работаю в проекте, который использует Node.js для Haraka (сервер smtp).

Это Node.JS, и у меня есть небольшая проблема с обратными вызовами. Я не смог преобразовать этот конкретный код для использования обратного вызова.

Итак, это код, который у меня есть:

exports.hook_data = function (next, connection) {
    connection.transaction.add_body_filter('', function (content_type, encoding, body_buffer) {
        var header = connection.transaction.header.get("header");
        if (header == null || header == undefined || header == '') return body_buffer;

        var url = 'https://server.com/api?header=' + header ;
        var request = require('request');
        request.get({ uri: url },
          function (err, resp, body) {
              var resultFromServer = JSON.parse(body);
              return ChangeBuffer(content_type, encoding, body_buffer, resultFromServer);
          }
        );
    });
    return next();
}

Этот код не работает, потому что он не ожидает обратного вызова запроса для продолжения. Мне нужно закончить запрос до next();

И это требования:

  1. В конце exports.hook_data обязательно вернуть next(). Но вернуть его нужно только после запроса.
  2. Мне нужно вернуть Buffer в add_body_filter, но мне нужно создать буфер с информацией, получаемой с сервера.
  3. Чтобы сделать запрос на получение, мне нужно использовать параметр (header), который есть только внутри add_body_filter.

Поэтому проблема в том, что я не могу сделать запрос до add_body_filter и поместить результат в обратный вызов, потому что параметр, который мне нужен для запроса, находится только внутри add_body_filter.

Какой-нибудь совет, пожалуйста?

14
Ricardo Polo Jaramillo 15 Дек 2015 в 23:16

4 ответа

Лучший ответ

Если вы не хотите использовать синхронные блокирующие функции, невозможно выполнить нумерованные требования.

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

Что касается номинальной стоимости, глядя на код, который у вас есть, я бы искал способ изменить контракт exports.hook_data, чтобы вы могли вызывать next() из request.get Перезвоните.

4
Hurricane Hamilton 15 Дек 2015 в 20:31

Изучите руководство Haraka для объекта транзакции и объект заголовка Я не вижу зависимости заголовка от add_body_filter. Также ваш код не показывает никакой зависимости от add_body_filter. Итак, ваше третье требование выглядит недействительным.

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

exports.hook_data = function (next, connection) {
    var header = connection.transaction.header.get("header");
    if (header == null || header == undefined || header == '') {
        return next();

    var url = 'https://server.com/api?header=' + header ;
    var request = require('request');
    request.get({ uri: url },
        function (err, resp, body) {
            var resultFromServer = JSON.parse(body);
            connection.transaction.add_body_filter('', function (content_type, encoding, body_buffer) {
                return ChangeBuffer(content_type, encoding, body_buffer, resultFromServer);
            });
            next();
        }
    );
}

Если в руководстве Haraka не удалось выделить зависимость заголовка от add_body_filter и / или вы обнаружили его на основе своего практического опыта, тогда подход Quy, похоже, является подходящим вариантом.

Если вам интересно, когда использовать next () v / s вернуться далее ()

0
Community 23 Май 2017 в 10:29

Используйте Async.js или Обещания.

Асинхронная реализация:

exports.hook_data = function (next, connection) {
  async.waterfall([
    function( done ) {
      connection.transaction.add_body_filter('', function( content_type, encoding, body_buffer ) {
        var header = connection.transaction.header.get("header");
        if ( header == null || header == undefined || header == '' ) {
          done(null, body_buffer);
        }
        done(null, header);
      });
    },
    function( header, done ) {
      var url = 'https://server.com/api?header=' + header;
      var request = require('request');
      request.get({ uri: url },
        function( err, resp, body ) {
          // do something if there's an error
          var resultFromServer = JSON.parse(body);
          done(null, ChangeBuffer(content_type, encoding, body_buffer, resultFromServer));
        }
      );
    }
  ], function( error, buffer ) {
    // do something if there's error
    next(buffer);
  });
}

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

Опять же, поскольку все они асинхронные, Node отправляет эти задачи в цикл событий ввода-вывода, и об этом позаботятся (неблокирование). Когда этот поток ожидает, он, вероятно, перейдет к следующему запросу, пока этот запрос ожидает.

1
Quy 20 Дек 2015 в 03:43

JavaScript является асинхронным по своей природе. Асинхронное программирование шаблон, который обеспечивает функцию неблокирующего кода, т.е. остановить или не зависеть от другой функции / процесса для выполнения конкретная строка кода. Ссылка: Статья Codementor

Из Википедии

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

Что ты можешь сделать?

  1. Используйте сон / ожидание, т. Е. setTimeout (не рекомендуется)
  2. Используйте некоторую асинхронную библиотеку, например https://github.com/caolan/async (рекомендуется)
  3. Используйте некоторые обещания, например Q
0
Marcel Djaman 24 Дек 2015 в 17:09