Pull to refresh

Comments 114

хабрапарсер поел букву 'c'
UFO just landed and posted this here
Вы хоть бы писали в одной ветке, через пару десятков сообщений, расстояние между вашими комментариями увеличится и смысловая связь между ними ослабнет
Признаю свою ошибку. Жал не ту ссылку.
Очень сложно это сделать — описания нет, а нечто напоминающее видео хочет плагин от MS.
Брр, какой-то Prototype поверх jQuery.
Что мешает поставить Silverlight или Moonlight?
Я тут пытаюсь Flash снести нафиг. Зачем мне еще одно дырявое тормозилово?
Flash я у себя снес, а вот Silverlight оставил — потому что конференции через него смотрю.
А у MS шикарно реализовано передача потокового видео. Он определяет возможности твоего канала и передает видео в том качестве, которое ты можешь принимать, что бы поток не приходилось буферезировать.

html5 такого не даст.
> html5 такого не даст.

а это и не задача html5. это задача реализации видео в html5.
в каждом конкретном браузере, есличо.
Эм, как это вообще решит это реализация html5?
MS предоставляет решение не только с плагином на клиенте, но и с распределенным ПО на серверах…

и есличо, это не задача реализации видео в html5
а как быть если у человека другая платформа?
Какая разница, какая у него платформа? Вы используете клиентскую часть, а она есть под linux, windows, mac os.

Трафик гонится через ближайший для вас медиа-сервер со качеством, которое будет меняться плавно так, что бы вы просматривали потоковое видео без буферизирования.

Например недавняя PDC 2010 использовала это решение. О том, что я пропустил хоть секунды конференции работая через wifi и двигаясь по офисному здания не было и речи. (тут я намекаю, что качество wifi сигнала скакало)

p.s.
привет торрлям которые засрали карму
Кирил, карму твою я не засырал, хотя бы по тому, что сам ее не имею. По теме, html 5 лучшее решение данной проблемы.
Ну, я не конкретно вам это написал.

HTML5 тут вообще не при чем.
Какая бы не была реализация тега video — это не поможет, т.к. отдачей потока(контента) занимается серверная часть.

В данном дереве комментариев, я лишь хотел показать, почему я оставляю silverlight(moonlight) в браузере у себя, falsh — как удаляю.

Но в связи с тем, что увы, на хабре много… эм… людей, которые вскормлены маркетингом — даже не стараются понять о чем идет речь, а сразу лезут в карму и опускают её.
ок, привет стереокиллеру :)
Данное решение некрасиво на больших количествах колбеков, не лучше ли каунтить сделанный запрос, а при получении колбека каунт декрементировать? Каунт = 0 — тот самый момент. В этом случае не нужно именовать и перечислять колбеки.
Не получится ли так, что не все еще запросы посланы, а предыдущие уже закончились и каунт равен 0?
Можно изначально установить count в количество отправляемых запросов и послать их все (Или не все, некоторые можно отложить).
Да, тоже в итоге пришел к этому решению
зашел прочитать этот комментарий :)
Ну теоретически не должно, но для надежности можно задать общее количество запросов.
Это немного другая задача. Разница в том решение топик стартера устойчиво к повторениям событий, а ваше — нет.
Да нет, в сабже ясно написано:

Нам надо отправить два асинхронных запроса и обработать их результат только после того, как будет получен результат обоих… Но особенность асинхронных запросов в том, что мы не знаем, какой из них придёт первым


То бишь задача — выполнить определенный колбек, как только получены результаты всех запросов, отправленных асинхронно.
И что запросы не могут придти дважды?
И что запросы не могут придти дважды?


Не совсем понял смысл вопроса. На один запрос — один колбек. Вы таки про колбеки спрашиваете, или про запросы?
Что не бывает случаев когда событие на которое вешается колбэк случается несколько раз, и соответственно колбэк вызывается не один раз а несколько?
Приведите пример, о каких таких случаях вы говорите?
да блин, банально два триггера — один от нажатия мышки на кнопку, второй от клавы на… пусть будет Ctrl.
Но вообще мне надавно пришлось делать перезапросы ajax-ом на сервера потому что там было несколько десятков событий, которые агрегировались в общий запрос на каждый сервер, но нужно было в конце концов получить все.
да блин, банально два триггера — один от нажатия мышки на кнопку, второй от клавы на… пусть будет Ctrl.


Сабж про ajax запросы, а не обработку событий dom.

Но вообще мне надавно пришлось делать перезапросы ajax-ом на сервера потому что там было несколько десятков событий, которые агрегировались в общий запрос на каждый сервер, но нужно было в конце концов получить все.


Это частная задача, и решение её будет частным.
да? ну не буду спорить :)
Сабж про асинхронные запросы, а не ajax запросы.
Там есть и запрос к базе и запрос к бд. И это могут быть любые асинхронные запросы, в т.ч. события dom.
Wott прав
Ок, сенькс за пояснение.
сабжевый способ эту проблему не решает.
в данном решении именование колбеков еще влияет на имена аргументов. А как Вы будете запоминать результаты?
и каждый раз при добавлении нового запроса, будем исправлять два значения count? тоже не сильно красиво. чтото мне подсказывает, что весь сыр бор здесь ни к чему не приведёт. имхо, нет изящного решения, которое бы устраняло эту проблему. проблема лежит немного глубже — в природе асинхронных запросов, они — асинхронны, а соответственно, мы не должны знать, какой из них придёт первым(по задумке создателей), а всё что мы выдумываем для этого — велосипед…
а в топике мы и не знаем, какой из запросов придёт первым. нам, на самом деле, абсолютно всё равно, какой придёт первым.
изначально я тоже думал сделать на основе каунтера
var process = processFsAndDb.after(2);

asyncFsAccess( file, process);
asyncDbAccess(query, process);


Но вынес именно те недостатки, что назвал Wott:

1. Повторение
Допустим, мы можем ждать повторяющегося события, нажатие кнопок A, B. Тогда пользователь может дважды нажать кнопку A и событие сработает
var process = processFsAndDb.after(2);

onKeyDown('A', process);
onKeyDown('B', process);


Другой вариант — если пользователь нажал «ентер» и данные уже скачаны аджаксом — должна начатся обработка данных.
var process = processFsAndDb.after(2);

onKeyDown('enter', process);
ajax(url, process);

Очевидно, он может дважды нажать ентер, а данные еще не скачены.
На самом деле ситация редкая, но почему бы её не предвидеть, учитывая, что есть еще недостатки

2. Аргументы
Как в этом примере узнать, где ответ от какой функции? args[0] — это ответ asyncFsAccess или asyncDbAccess?
var process = processFsAndDb.after(2);

asyncFsAccess( file, process);
asyncDbAccess(query, process);


3. Читабельность
Со мной, конечно, могут поспорить, но я считаю, что понятнее вторая строка:
var process = processFsAndDb.after(2);
var process = processFsAndDb.after('keyPressed', 'ajaxComplete');
Вполне логично. Просто я посмотрел на сабж немного в другой плоскости, например простая ситуация: мы асинхронно грузим и выполняем пачку скриптов. В этом случае каунтер предпочтительнее.
К сожалению вся красота пропадет если добавить еще валидацию принятых данных…
А так ничего — прикольно.
валидация в processFsAndDb, не?
можно и так, но ведь можно же в нем и проверять наличие всех данных, а не делать для этого отдельную обертку :)
смысл в том что бы разделять разные процессы ( это еще хорошо для обработки ошибок ). Именно этим мне и понравилось Ваше решение.

Я тут выше описал ситуацию когда полученный запрос неплохо бы перезапросить, прежде чем проверять наличие остальных данных. И уже по готовности и валидности всех данных — обрабатывать. В общем мухи — отдельно, котлеты — отдельно.
ну да есть смысл. но это решение универсальное.
Раз пошла такая пьянка, то думаю стоит упомянуть про Deferred. Выглядело бы примерно так
var fileData;
var dbData;

next(function(){
    return asyncFsAccess(file).next(function(data){fileData = data})
}).
next(function()
    return asyncDbAccess(query).next(function(data){dbData = data})
}).
next(function(){
    return processFsAndDb(fileData, dbData)
})


По поводу Function.prototype.after — мне кажется что после выполнения onReady стоит очищать хеши after и ready.
Чем этот вариант отличается от варианта автора под названием «Фиг с ним, подожду»?
Как минимум тем что вместо каллбеков цепочки, т.е. код становится более читабельным. Плюс значительно упрощается отлов ошибок через метод .error

...
next(function(){
    return asyncFsAccess(file).next(function(data){fileData = data})
}).
error(function(e){
    console.log(e)
})
...
Только этим и отличается, но сам принцип лучше не становится.
Как по мне — разница значительна. Если вы намекаете на параллельность запросов — то делается это так:
parallel([
	asyncFsAccess(file),
	asyncDbAccess(query)
]).
error(function(e){
    console.log(e)
}).
next(function (results) {
	processFsAndDb.apply(this, results)
});
В вашем примере asyncFsAccess и asyncDbAccess вызовутся синхронно.
Как раз нет, в методе parallel к каждой из функций добавится цепочка .next(...).error(...), результаты которых передадутся вниз по цепочке. Тут можно почитать описание.

по-первых, ваша ссылка отвечает мне «Страница, которую вы пытаетесь просмотреть, не может быть показана, так как она использует неверную или неподдерживаемую форму компрессии.»

во-вторых, посмотрите внимательно, что вы написали. asyncFsAccess — это функция, которую вы вызываете, а не передаёте параметром в parallel. то есть в parallel передастся не нужная нам функция, а результат её выполнения.

решение — поступить, как tenshi — биндить аргумент к функции, если вы расширили прототип ф-ции и у вас есть такой метод.
открылась. и я прекрасно понимаю, что это значит. но внимательно почитайте моё предыдущее сообщения.
вместо биндения аргументов в deferred используется «самовызов» из callback'a, т.е. как-то так:

parallel([
    (function(){
        var d = Deferred();
        setTimeout(function () {
            d.call('value1');
        }, 100);
        return d;
    })(),
    
    (function(){
        var d = Deferred();
        setTimeout(function () {
            d.call('value2');
        }, 100);
        return d;
    })()
]).
next(function (results) {
	console.log(results);
})
смотря как его готовить. можно один раз всунуть deferred, например, в свою AJAX функцию
а на базу чужих фреймворковв?
на сколько я знаю — существуют реализации deferred на всех популярных фреймворках, т.е. при подключении этой библиотеки интегрируются как минимум в AJAX.
function http_get(url) { 
    var d = Deferred();
    var xhr = new XmlHttpRequest();
    xhr.open("GET", url, true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState != 4) return;
        if (xhr.status==200){
            d.call(xhr.responseText);
        } else {
            d.fail(xhr.statusText);
        }
    }
    xhr.send(null);
 
    return d;
}


а дальше вполне красиво себе использовать
елки, второй раз само отправилось…

использовать:
parallel([
    http_get('foo.html'),
    http_get('bar.html')    
]).
next(...)


Есть замечательная библиотека Step. С помощью нее ваш код будет выглядит так:
  1. Step(
  2.   function() {
  3.     asyncFsAccess(file, this.parallel());
  4.     asyncDbAccess(query, this.parallel());
  5.   },
  6.   function(err, fileData, dbData) {
  7.     processFsAndDb(fileData, dbData);
  8.   }
  9. );
* This source code was highlighted with Source Code Highlighter.


Удобнее, не находите?
Она как раз через counter сделана. Что лично мне кажется недостатком.
Мне та что в топике больше нравиться — можно process.fn() вызывать где угодно, не привязываясь к замыканию. А без оного — все тоже же самое.
ИМХО, если не критична скорость, то лучше воспользоваться надежным вариантом… С последовательными вызовами…
В ExtJS Ext.Direct, параллельные асинхронные запросы, при условии что вызываются в определенном интервале времени, отрабатываются на самом деле одним запросом, реализация конечно сокрыта в недрах библиотеки.
чем лучше?) скорость всегда критична.
шаманство какое-то.
лучше так:

Sync()
.thread( asyncFsAccess.bind( file ) )
.thread( asyncDbAccess.bind( query ) )
.finalizer( processFsAndDb )
.run()

asyncFsAccess( file, process['fs']);
asyncDbAccess(query, process['db']);
и когда вызывать функцию Sync?
глупый вопрос.

две последние строчки у меня — ненужный артефакт
окей, что за метод такой, .thread()?
добавляет асинхронный поток. разве не очевидно?
Выглядит красивее. А две последние строчки для чего?
тогда уж можно даже так:
Sync()
  .thread( asyncFsAccess.bind( file ) )
  .thread( asyncDbAccess.bind( query ) )
  .run( processFsAndDb );
нет. в твоём случае при каждом вызове придётся указывать обработчик, а это не удобно.
иногда удобно. думаю, вполне можно сделать и так и так.
Async.js умеет. В браузере и на сервере. По цепочке, параллельно, водопадом (когда результат одной асинхронной функции передается на вход следующей) и много еще чего. Для меня лично — самый понятный вариант среди всех async и combo библиотек и подходов. Использую на нескольких проектах, пока не подводил.
мне этого не хватало :) спасибо
Уже с год для программирования сложных анимированных интерфейсов пользую свой простенький класс AfterAll.
Интерфейс:
var after = new AfterAll;
after.addAfterAllCB(function(){$('#screen').hide();});

$('#bar').animate({top: 30}, 1000, after.getCB(function(){$(this).hide()}));
$('#ov').fadeOut(100, after.getCB());

тобишь можно еще калбеки для каждого отдельного действия добавлять.
Я думаю этот патч не будет принят из-за несовместимости с некоторыми браузерами.
Ой, не та вкладка, извиняюсь
этот патч совместим со всеми браузерами. точнее не так.
те, кто не использует геттеры и сеттеры — ничего не узнают про этот патч, он на них не повлияет никак. а вот те, кто использует — сможет использовать их и в Мутулз.
Ок, а если так? jQuery.one тут только чтобы код был короче
function EventCollector(cb, manyTimes) {
	var q = 0;
	this.add = function( target, evt ){
		++q;
		$(target).one(evt, function( evt ){
			if( --q < 1 ) {
				cb();
			}
		});
		return this;
	};
};

var Obj = new (function(){
	var self = this;
	this.async = function() {
		setTimeout(function(){
			$(self).triggerHandler('async');
		}, 1000);
	};
})();

var evc = new EventCollector(function(){
	alert('all done');
});
evc.add('button', 'click');
evc.add(Obj, 'async');

Obj.async();
простите, не совсем понял ваше предложение.
можете пояснить на примере?
Я предлагаю использовать события а не коллбеки.
т.е. это могут быть и нативные события, но в примере я использовал жкверевскую модель.
Это простенький класс с каунтером, который вешает события на объекты, а потом ждёт их все. Вызовом СВОИХ событий занимается каждый объект сам.

Чуть упростил, может так лучше:

function EventCollector(cb, delay) {
	var q = 0;
	function evtDone(){
		if( --q < 1 ) {
			cb();
		}
	}
	this.one = function( target, evt ){
		++q;
		$(target).one(evt, evtDone);
		return this;
	};
	this.delay = function( time ){
		++q;
		setTimeout(evtDone, time);
		return this;
	};
};



var evc = new EventCollector(function(){
	alert('all done');
});
evc.one('button', 'click').delay( 1000 );
понял. вариант с событиями интересный.
но, кажется, более многословный.
надо смотреть по ситуации.
и продумать его, потому что пока что не очень внятный апи.
UFO just landed and posted this here
т.е. по сути у вас получилась разновидность реализации паттерна Observer?
UFO just landed and posted this here
Как вариант сделать «стек» запросов, который при инициализации заполняется нужными запросами, после чего происходит их асинхронный запуск, после того как на любой из запрос вернулся результат, удалить этот запрос из стека, а после того как стек опустеет вызвать колбек…
Самый верный способ — положить на backend скрипт, который может менять в цикле $_POST / $_SERVER['REQUEST_URI'] (если это PHP) и делать нужный include().

А далее всё просто:

queue = new $.queue('id1', '/test/_f1', {'a' : 11});
queue.add('id2', '/test/_f2', {'a' : 12});
queue.add('id3', '/test/_f3', {'a' : 13});
queue.send(
    function(data)
    {
         response1 = data.id1;
         response2 = data.id2;
         response3 = data.id3;

    }
);


бонус: не дёргаем лишний раз сервер
В варианте «7 раз проверь ++» нет вызова функции process(), лучше поправить.
UFO just landed and posted this here
А у когото было такое?
TypeError: asyncAbAccess(...) is not a function
хотя весь код данных функций как в примере исполняеят но по окончании ошибка и все дальше код не идет +(
суть не в том — я просто поменял букву, суть в тому что после объявления «процесс»
var process = processFsAndDb.after('fs', 'db', "ab");
ни 1 функция уже не работает — точнее так:
function zxc(a){console.log(a)}; zxc(2)
TypeError: zxc(...) is not a function
Напишите весь код, пожалуйста)
function asyncFsAccess(a, c){
	console.log(a)
	if (c) c()
};
function asyncDbAccess(b, c){
	console.log(b)
	if (c) c()
};
processFsAndDb = function(){
	console.log("done",arguments);
}

function asd(a){
	console.log(a)
	//if (c) c()
};
function zxc(a){log(a)}
asd(3)
var process = processFsAndDb.after('fs', 'db', "ab");
//asyncFsAccess( 1, process.fs)
//asyncDbAccess( 2, process.db)
zxc(2)
мда, смешно даже както, ошибка была устранена после знака ";" в конце строки вызова первой функции после объявления «process»
zxc(2);

странно както, вдеь должно само автоматом закрывать при компиляции кода…
Sign up to leave a comment.

Articles