Мой синхронный костыль
Продолжаю графоманить. На этот раз предлагаю свой способ поочередного вызова асинхронных функций (таймаутов, анимаций, аяксов и пр.) и избегания ужаса вложенных колбеков.
Для этого вызываем функцию waiting, затем по цепочке вызываем метод wait. Аргументом waiting и wait служит колбек, определенный в примере, как runNext. Его вызов запускает очередную порцию кода. Для проверки работы откройте консоль. (function(){ window.wait = function(first){ return new (function(){ var self = this; var callback = function(){ var args; if(self.deferred.length) { args = [].slice.call(arguments); args.unshift(callback); self.deferred[0].apply(self, args); self.deferred.shift(); } } this.wait = function(run){ this.deferred.push(run); return self; } this.deferred = []; first(callback); }) } /* Пример */ wait(function(runNext){ console.log('Run 1'); setTimeout(function(){ runNext(1,2); //передаем какие-нибудь аргументы в следующий вызов }, 1000); }).wait(function(runNext, a, b){ console.log('Run 2, a='+a+' b='+b ); //используем аргументы из предыдущего вызова setTimeout(runNext, 1000); }).wait(function(runNext){ console.log('Run 3'); setTimeout(function(){ console.log('End 3') runNext(); }, 1000); }).wait(function(runNext){ console.log('Run 4'); setTimeout(runNext, 1000); }).wait(function(){ console.log('Last one'); }); })(); Пример с анимациями http://jsfiddle.net/finom/XSGub/37/ |
Что-нибудь можешь прокомментировать по моей идеи?
http://habrahabr.ru/blogs/javascript...omment_4479560 |
B~Vladi, то что ты предложил несколько выходит за рамки моих знаний, поэтому компетентного ответа я дать не могу.
|
Я всё-таки допилю до юзабельного варианта и выложу.
|
не слишком гибко, когда для вызова следующей функции из цепочки обязательно вызывать runNext. конечно, для передачи аргументов в следующий вызов она как раз подходит, но для того, чтобы просто вызвать следующую функцию (99%), потребутся вводить заветные буквы.
возможно ли ту функцию сделать необязательной ? как в этом случае будет обрабатываться время следующего вызова ? |
melky,
А как узнать, что тот же таймаут завершился? Только по коллбеку. Цитата:
|
да. в этом случае можно указывать параметр, является ли блок кода полностью синхронным, или нет (ajax, напр.). если код async:false (default), если же он async:true - будьте добры тогда указать сами, когда он закончит исполнение (runNext)
|
Не знаю есть ли в этом смысл. В любом случае, придется писать
wait(function(){ this.async = false; }) вместо wait(function(){ this.next(); }); |
вы правы. оно нафиг не нужно, потому что (я прикинул) для этого придётся дописывать много кода в вашу функцию, и вообще, "овчинка не стоит выделки",т.к. при таком подходе передача аргументов осложняется.
|
экспериментировал с подобными штуками . функционал получался такой-же как у вас. Пробовал использовать в практике, но в итоге получается что проще классическим способом написать код или немного поменять алгоритм.
сейчас подумываю упростить. получается что-та вроде цепочки с паузами. var sync = new ....; setTimeout(sync(), 1000); setTimeout(sync(), 100); sync(function() { }); setTimeout(sync(), 100); var xx = sync(); sync(function() { .... setTimeout(xx, 1000); .... }); sync(function() { }); |
Цитата:
FINoM, если надо передать данные через несколько функций их прийдется "протаскивать" через аргументы. Лучше наделить цепочку состоянием, что-то типа: this.state('var', ...); // изменение переменной this.state('var') // получение значения переменной и... названия какие-то странные, может лучше так: chain(function() { ... }).then(function() { ... }).then(function() { ... }); |
ниче не понял, а зачем вообще это? вызывать четко по очереди или просто нужна задержка между вызовами функций?
|
вызывать четко по очереди
у меня вывод такой FF: Run 1 undefined Run 2, a=1 b=2 Run 3 End 3 Run 4 Last one |
хм... а разве обычный вызов:
func1(); func2(); func3();не по очереди вызываются? |
devote,
setTimeout в одну из первых двух поставь |
Цитата:
|
Цитата:
Цитата:
|
devote, это актуальнее для nodejs, хоть и на клиенте может быть надо.
Цитата:
this.state = function(name, value) { if (arguments.length) { this._state[name] = value; return this; } else { return this._state[name]; } } Цитата:
|
Теперь не обязательно заботиться о целостности цепочки: http://jsfiddle.net/finom/XSGub/50/
|
x-yuri, я тебе позже отвечу, а то мозг не варит.
|
Цитата:
как пример применения. нужно сделать несколько асинх. запросов, дождаться их завершения и выполнить какую-то функцию. Тоесть ставим несколько блокировок, а после них нужную функцию. А вот в методом FINoM такое не сделать. |
vflash, так тебе не цепочка, а defered тогда нужен
|
Цитата:
Цитата:
|
к тому что на данный момент ты подразумеваешь, что значения будут передаваться между соседними функциями
waiting(function(runNext) { runNext(1, 2, 3, 4, 5, 6, 7, 8, 9); }) .wait(function(runNext, v1, v2, v3, v4, v5, v6, v7, v8, v9) {...}) .wait(function(runNext, v1, v2, v3, v4, v5, v6, v7, v8, v9) {...}) .wait(function(runNext, v1, v2, v3, v4, v5, v6, v7, v8, v9) {...}) .wait(function(runNext, v1, v2, v3, v4, v5, v6, v7, v8, v9) { // и только здесь нам пригодятся эти значения }) альтернативный вариант new AsyncChain() .add(function(NEXT) { this.state('a1', 1); this.state('a2', 2); this.state('a3', 3); this.state('a4', 4); this.state('a5', 5); this.state('a6', 6); this.state('a7', 7); this.state('a8', 8); this.state('a9', 9); NEXT(); }) .add(function(NEXT) {...}) .add(function(NEXT) {...}) .add(function(NEXT) {...}) .add(function(NEXT) { // а теперь используем их, this.state('a...'); }) .go(); |
x-yuri, не вижу смысла городить такой костыль. Человек, если ему захочется передавать через всю цепочку состояния переменных, может просто-напросто передавать объект.
wait(function(next){ var states = {a: 1, b: 2} next(states); }).wait(function(next, states){ states.c = 3; next(states); }).wait(function(next, states){ states.d = 4; states.e = 5; }); |
http://jsfiddle.net/finom/XSGub/52/ — сделал сделал this для всей цепочки одним объектом (раньше в первой функции this === window). Функции get и set здесь излишни, как по мне.
wait(function(next){ this.blabla = {a:1,b:2} next(); }).wait(function(next){ this.blabla.c = 3; next() }).wait(next) { log(this.blabla); // {a:1, b:2, c:3} }); |
Можно присоединится?,
сейчас в голову велосипед приехал: var chain = function () {}; chain.prototype.deferred = []; chain.prototype.add = function (fn) { this.deferred.push(fn); return this; } chain.prototype.next = function () { if (this.deferred.length) { this.deferred.shift().apply(this); } } chain.prototype.start = function () { this.deferred.shift().apply(this); } new chain(). add(function(){ var self = this; setTimeout(function () { console.log(1); self.next(); }, 1000); }). add( function(){ var self = this; setTimeout(function () { console.log(2); self.next(); }, 1000); }). add( function(){ console.log(3); }). start(); |
Цитата:
w = function(){ return wait(...).wait(...) } w(); Цитата:
var self = this;тоже кажется излишним. + у тебя теряется целостность. Если последний коллбек сработал, следующие звенья не запустятся. |
Цитата:
var chain = function () {}; chain.prototype.deferred = []; chain.prototype.add = function (fn) { this.deferred.push(fn); return this; } chain.prototype.next = function () { if (this.deferred.length) { this.deferred.shift().apply(this); } } chain.prototype.start = function () { this.deferred.shift().apply(this); } var a = new chain(). add(function(){ var self = this; setTimeout(function () { console.log(1); self.next(); }, 1000); }). add( function(){ var self = this; setTimeout(function () { console.log(2); self.next(); }, 1000); }). add( function(){ console.log(3); this.next(); }); setTimeout(function(){ console.log('добавим чего-нибудь в цепь'); a.add(function(){ console.log(4); }).start(); },2000); Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
|
Цитата:
Т.к. функции добавляются в стек, то и выниматься они будут в той же последовательности. Поэтому никаких нарушений работы скрипта не предвидится. Я к тому веду, что как мне используя твою функцию собрать цепочку, но не запускать её? Обернуть в функцию, а потом ещё раз и ещё раз, добавляя по звену, если мне нужно собирать звенья через таймауты(допустим ajax)? Примеры получаются какие-то абстрактные. |
По поводу передачи переменных между функциями я буду использовать сеттеры/геттеры, меньше геморроя, а код понятнее. Я как-то делал подобным образом, как у тебя. Если код разрастается фиг поймешь что, куда передал.
|
Цитата:
w = function(last){ return wait(function(next){...}).wait(function(next){...}).wait(last) } потом, если хочешь запустить, добавив еще функций в стек, пишешь: w(function(next){...}).wait(funciton(next){...}).wait(function(next){...}); |
Я уже запутался, что и как вызывать. То w добавляет в цепочку, то wait да ещё и в функцию обернуть.
Останемся каждый при своём, тебе наверное так удобнее. Кстати: var self = this; можно не писать, если сделать так: var c = new chain(); c. add(function(){ setTimeout(function () { c.next(); }, 1000); }). ... |
Цитата:
Цитата:
ты можешь упираться ногами и руками против использования объектов, но что это тебе даст? Цитата:
|
Цитата:
Если погуглить, то асинхронные приложения писались задолго до появления NodeJS и уже выработались соответствующие паттерны. Но в JS как всегда всё по-своему :) |
я считаю, что есть прямые пути, а есть обходные. Я предпочитаю ходить напрямик, если нету причин ходить в обход. Ваши причины для меня не причины (недостаточные причины). Нехватка знаний/опыта ни при чем. Они в лучшем случае (или худшем, это как посмотреть) помогают ходить в обход, но с причинами никак не связаны. И если так, то даже хорошо, что не хватило. ;)
а асинхронное программирование, о котором можно погуглить, - нечто совсем отличное от асинхронного программирования в js. Цитата:
|
Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
...продолжу. FINoM, ты стараешься не усложнять. Это твоя причина. Я тоже так старался делать. Но в результате такие решения не выдерживали столкновения с практикой и приходилось их доделывать. B~Vladi, ты делаешь вид что проблемы не существует в ущерб разбиению на классы что ли. Причина: производительность и прямолинейность. Прямолинейность делает реализацию прозрачной, но при этом сложно увидеть намерения. Прозрачность намерений или выразительность - это тот самый прямой путь, о котором я говорил. |
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
|
Часовой пояс GMT +3, время: 23:19. |