
Продолжая тему Deferred для JavaScript предлагаю еще одно переписывание Deferred, теперь в терминах Prototype. Подробнее о самом Deferred можно почитать в двух моих прошлых заметках: Асинхронное программирование: концепция Deferred и Deferred: все подробности. Если кратко, самое распространенное и полезное применение Deferred в JavaScript — это работа с AJAX или другими RPC-over-HTTP вызовами, когда необходимо совершить цепочку логически связанных вызовов, корректно обрабатывать возникающие ошибки и т.п. С моей точки зрения, Deferred крайне необходим в таких ситуациях.
Перейдем к примерам: обращение к некоторому JSON-RPC API на основе Prototype’овского Ajax.Request можеть быть обернуто в Deferred следующим образом:
var Api = Class.create({ initialize: function(url) { this.url = url; }, call: function(method, params) { var requestBody = $H({ 'method' : method, 'params' : params }).toJSON(); var d = new Deferred(); var onSuccess = function(transport) { result = transport.responseText.evalJSON(); if ('faultCode' in result && 'faultString' in result) { var err = new Error(result.faultString); err.faultCode = result.faultCode; err.faultString = result.faultString; d.errback(err); } else { result = result[0]; console.log("Got result: ", result); d.callback(result); } }; var onFailure = function(transport) { d.errback(new Error("API transport error: " + transport.status)) }; var onException = function(error) { d.errback(error); } new Ajax.Request(this.url, { method: 'post', postBody: requestBody, requestHeaders: { 'Content-Type' : 'application/json' }, onSuccess: onSuccess, onFailure: onFailure, onException: onException, }); return d; }, });
Здесь любое обращение к
Api.call будет возвращать новый Deferred, который будет содержать результат удаленного вызова либо исключение (транспортное или от сервера, к которому мы обращаемся). Пусть есть RPC-вызовы sum и mult, которые, соответственно, складывают и перемножают свои аргументы. Тогда вычисление выражения (2+3)*7 с использованием нашего класса Api будет выглядеть так:var api = new Api; api.call('sum', [2, 3]) .addCallback( function (sum_of_2_and_3) { return api.call('mult', [sum_of_2_and_3, 7]); }) .addCallback( function(result) { alert('(2+3)*7 = ' + result); }) .addErrback( function (error) { alert('Mmm… something wrong happened: ' + error); });
Ну и самое главное:
- исходный код Deferred.js;
- лицензия MIT, как и у самого первого варианта Deferred для JavaScript.