Шаблоны проектирования JavaScript - Работа с нежелательной асинхронностью

Я новичок в программировании на основе событий (используя node.js). Я считаю, что там что-то я просто не понимаю, потому что есть особая проблема, с которой я постоянно сталкиваюсь снова и снова.

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

Например: прямо сейчас я пишу некоторые материалы, которые сильно используют mranney node -redis library. Моя программа очищает RSS-каналы и перетаскивает результаты в redis. Я использую то, что, по моему мнению, является общей стратегией с redis:

  • Скопировать фид, сохранить результаты в виде хэша redis с помощью клавиши чего-то вроде feed:<feedId>:results:<timestamp>.
  • Сохраните ссылку на последний результат в feed:<feedId>:latest.
var redis = require("redis");
var client = redis.createClient();

var get_latest_results = function (feedId) {
    client.get('feed:+ feedId + ':latest', function (err, res) {
        var latest_reading_key = res.toString();
        client.hgetall(latest_reading_key, function (err, res) {
            var latest_reading = res;
        });
    });
    // how do I specify a return value for this function?
}

Размещение return latest_reading в нижней части функции get_latest_results завершается с ошибкой, поскольку last_reading не определен до тех пор, пока функция не будет готова к завершению. Размещение return latest_reading в вызове hgetall завершается с ошибкой, потому что return ссылается на обратный вызов и игнорируется get_latest_results.

Это всего лишь один пример такой ситуации, в которую я, похоже, постоянно писал свой путь. Может быть, я пытаюсь колотить квадратную привязку в круглую дыру, потому что я не знаю ничего лучше. Кажется, что должен быть нехарактерный способ решения этого класса проблем.

Ответы

Ответ 1

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

В асинхронном режиме вы должны присоединить обратные вызовы к событиям. Вы не должны ожидать результата от асинхронной функции, такой как get_latest_results(), но вы должны передать ей функцию обратного вызова в качестве аргумента, который будет вызываться, когда результаты будут готовы. Обратный вызов будет делать все, что нужно сделать с вашими результатами:

var get_latest_results = function (feedId, readyCallback) {
    client.get('feed:' + feedId + ':latest', function (err, res) {
        var latest_reading_key = res.toString();
        client.hgetall(latest_reading_key, function (err, res) {
            readyCallback(res);                           //--- Trigger Callback
        });
    });
    // how do I specify a return value for this function? //--- You don't
}

Затем вы можете вызвать свою функцию следующим образом:

get_latest_results(1000, function (result) {
   //--- Do whatever needs to be done with the latest result...
});