2010-10-12 5 views
15

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

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

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

  1. Scrape корма, результаты магазин как Redis хэш с ключом что-то вроде feed:<feedId>:results:<timestamp>.
  2. Хранить ссылку на последний результат под 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 терпит неудачу, потому что latest_reading не не определен до после функция готова выйти. Размещение return latest_reading в вызове hgetall завершается с ошибкой, потому что return ссылается на обратный вызов и игнорируется get_latest_results.

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

ответ

28

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

В асинхронном режиме вы должны присоединить обратные вызовы к событиям. Вы не должны ожидать результата от асинхронной функции, такой как 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... 
}); 
+4

+1. Научитесь нравиться. 'cos JavaScript не дает вам примитивов на уровне языка, таких как потоки или сопрограммы, которые вам понадобятся для синхронного запуска асинхронного кода (или наоборот). – bobince