Шаблоны проектирования 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...
});