|
Упрощенный Deferred
Примерно тоже самое находиться в jQuery и Dojo, но здесь сильно упрощенный вариант (не продумана вероятность ошибок в обработчиках, нельзя указать контекст выполнения обработчиков и т. д.). Предназначен, чтобы разобраться, как это работает на простом примере и/или для допиливания (выкладывайте прямо здесь, что получается). Критика приветствуется.
/** * Id: deferred * */ (function() { var arraySlice = [].slice; function Deferred() { if (!(this instanceof Deferred)) { throw new TypeError(); } this._then = []; this.then.apply(this, arguments); } Deferred.prototype = { _resolved: false, then: function _(callback) { if (callback) { if (this._resolved) { callback(); } else { this._then.push(callback); } } if (arguments.length > 1) { _.apply(this, arraySlice.call(arguments, 1)); } return this; }, resolve: function() { if (!this._resolved) { this._resolved = true; var results = [], then = this._then, i = 0, l = then.length; while (i < l) { results[i] = then[i++].apply(null, arguments); } return results; } } }; Deferred.when = function() { var dfr = new Deferred(), count = 0; function resolveFunc() { if (!--count) { dfr.resolve(); } } for (var i = 0, l = arguments.length; i < l; ++i) { if (arguments[i]) { ++count; arguments[i].then(resolveFunc); } } return dfr; }; this.Deferred = Deferred; })(); // пример использования: var dfr1 = new Deferred(function() { console.log('dfr 1'); }); var dfr2 = new Deferred(function() { console.log('dfr 2'); }); Deferred.when(dfr1, dfr2).then(function() { console.log('dfr all'); }); setTimeout(function() { dfr1.resolve(); }, 2000); setTimeout(function() { dfr2.resolve(); }, 5000); UPD: полезные ссылки: 1, 2, 3, 4, 5. |
а слабо разобраться в этой штуке? ;-) http://forum.mozilla-russia.org/viewtopic.php?id=51812
|
Цитата:
|
угу, только с поддержкой исключений и на яваскрипте
|
для своего велосипеда сделал диферд следующей структуры:
var d = _.deferred() - создаёт объект. в моей реализации это типо суперкласс. d.stage('ajax') - создаёт стадию. таких стадий может быть сколько угодно. их можно: d.resolve('ajax') d.reject('ajax') d.stage('ajax').done(function() {...}).fail(function() {...}); ещё может передаваться контекст и параметры, можно выполнять без имени, тогда завершиться следующая стадия в очереди. если в d не осталось незавершённых стадий, он сам завершается, тут 3 варианта: success (все стадии resolve) err (хоть одна reject) anyway вроде всё... Как задумка?:) сам как написал, сел задумался: какая же х*рня. какое-то масло масляное(у меня ещё when есть). и тд и тп. но решил оставить. уже пару раз, с удивлением, словил себя на мысли, когда юзал его, мол "вау. так пригодилось, а я о таком даже не подумал". но чёт до сих пор сомневаюсь... |
я правильно понял, что на каждую созданную стадию, вы можете навешивать свои собственные обработчики, и вызывать их обработку для конкретной стадии?
По-сути, можно заменить массивом независимых Deferred, каждый из которых представляет свое состояние? Если да, то в чем смысл/польза? Если нет, то прошу пояснить подробнее идею. желательно с примерами, где она гармонично у вас вписывается |
Да, правильно.
Цитата:
Смысл/польза в том, что свой велосипед юзаю в риа. и там случаев, где надо делать массив больше, нежели где надо простой диферд. Код писал под пример(тоесть сначала написал пример, а потом код для реализации). Тут могут быть эм-ты фреймворка если что. var d = _.deferred(); // ##### --- stages actions d.stage('animation').done(function() { console.log('animation finished'); }).fail(function() { console.log('animation failed'); }); d.stage('ajax').done(function() { console.log('ajax done'); }).fail(function() { console.log('ajax fail'); }); d.stage('button'); // ##### --- actions _.post('some/url.php').succes(function(data) { d.resolve('ajax', data); }).err(function(err) { d.reject('ajax', err); }); _('.menu').hide(200, function() { if(this.length) { d.resolve('animation'); } else { d.reject('animation'); } }); _('.button-forward').click(function() { d.resolve('button'); }); _('.button-back').click(function() { d.reject('button'); }); // ##### --- defered finally d.success(function() { console.log('chain success'); }).anyway(function() { console.log('chain done'); }).err(function() { console.log('chain with err'); }); Вот. Я было попробовал это переписать короче - не получилось... Ещё из плюсов: не засирается область лишними переменными. +я изначально диферд сделал простым. тоесть все свойства создаются в момент навешивания обработчиков. так что можно не париться что колбасу режем скальпелем. |
судя по последним строчкам вы сделали DeferredList, который позволяет обращаться через себя к отдельным Deferred
Плюс добавление наблюдаемых объектов на лету. Вопрос на засыпку: что будет, если я после d.success() добавлю, а позже выполню еще одну стадию? сработает ли еще раз d.success с дополниельной стадией? |
Цитата:
то есть после выполнения диферда на него можно навешать ещё стадий. и выполнять их. но обраьботчики на дифферде сработают только 1 раз. признаться про это я не думал, когда делал(ну или мб забыл, ночь всё таки была:)). Цитата:
я забыл упомянуть, что и у самого диферда есть d.finish(). тоесть его самого можно юзать как простейший $диферд. d.anyway(function() {...}).anyway(function() {...}).anyway(function() {...}); d.finish(); В общем АД:D |
Цитата:
Цитата:
resolve-ит все объявленные стадии и глобальный обработчик? |
Часовой пояс GMT +3, время: 19:45. |
|