Comments 63
Асинхронные запросы синхронизировали, синхронизировали, да не высинхронизовали
+9
TheShock, интересует ваше мнение =)
Прикольно) В принципе, решение достаточно похоже на моё)
На самом деле — зависит от вкусов, что лучше — расширять прототип или использовать класс-враппер, тут можно похоливарить, но не имеет смысла)
Только не нашёл ответа на один вопрос — что будет, если мне надо синхронно выполнить три и больше запросов?
пс. Когда вообще, имхо, придётся использовать эту функцию — так это при асинхронных запросах к базе, если нам необходимо двумя и больше запросами выбрать из разных таблиц пачку данных и сгруппировать в orm.
+1
Если три и более — то же самое. Количество не органичено (ну… в разумных пределах, конечно) =)
0
… подправил фразу в первой строке.
0
допустим такую ситуацию.
нам надо указать три функции. на две из будут указаны и выполнены до того, как указана третья функция.
В предыдущем топике, кстати, был такой вопрос
ps. Предыдущая ссылка на топик сломалась, хабрапарсер — лох. вот корректная ссылка
habrahabr.ru/blogs/javascript/108298/
нам надо указать три функции. на две из будут указаны и выполнены до того, как указана третья функция.
В предыдущем топике, кстати, был такой вопрос
ps. Предыдущая ссылка на топик сломалась, хабрапарсер — лох. вот корректная ссылка
habrahabr.ru/blogs/javascript/108298/
+2
М… не так, как в том вопросе, но такое может произойти.
WaitSync.wrap() возвращает готовую функцию и попутно регистрирует ее у себя (он, кстати, помнит какая именно функция была создана и была ли выполнена). Косяк может возникнуть, если попробовать запустить одну из функций, не сгенерив хотя бы еще одну другую.
Например:
но если сделать вызов badFunction() после создания goodFunction, все будет ок.
WaitSync.wrap() возвращает готовую функцию и попутно регистрирует ее у себя (он, кстати, помнит какая именно функция была создана и была ли выполнена). Косяк может возникнуть, если попробовать запустить одну из функций, не сгенерив хотя бы еще одну другую.
Например:
var fail = new WaitSync(function () {
console.log('epic fail');
});
badFunction = fail.wrap(function () {
console.log(' imma carryin' damage!');
});
badFunction();
goodFunction = fail.wrap(function () {
console.log('too late :(');
});
setTimeout(goodFunction, 4000);
но если сделать вызов badFunction() после создания goodFunction, все будет ок.
0
Что касается побочных вызовов…
хотя wrap'у передается одна и та же функция, он генерит разные замыкания и регистрирует у себя две разные функции в итоге (поэтому он ждет, пока выполнятся обе, ну или больше).
Однако такой вариант:
то есть, в принципе, можно ту же самую сгенеренную функцию вызвать дважды. Но засчитана она будет лишь одинажды. Я думал сделать так, чтобы она вообще не выполнялась более 1 раза… но имхо в запутанном коде может быть непонятно, почему так… думаю так правильнее… мало ли… циклы там…
var test = new WaitSync(function () {
console.log('done');
});
var sameFunction = function () {
console.log('test');
};
var testFn = test.wrap(sameFunction);
var testFn2 = test.wrap(sameFunction);
testFn(); // не вызовет колбэк
testFn2(); // вызовет колбэк
хотя wrap'у передается одна и та же функция, он генерит разные замыкания и регистрирует у себя две разные функции в итоге (поэтому он ждет, пока выполнятся обе, ну или больше).
Однако такой вариант:
var test = new WaitSync(function () {
console.log('done');
});
var sameFunction = function () {
console.log('test');
};
var testFn = test.wrap(sameFunction); // генерит врап для первой функции
var testFn2 = test.wrap(function() {console.log ('somethingelse')}); // врап второй функции
testFn2(); // не вызовет колбэк, ждем testFn
testFn(); // вызывает колбэк
testFn(); // не вызывает колбэк, т.к. кого надо уже позвали, НО функция будет выполнена
testFn(); // аналогично
то есть, в принципе, можно ту же самую сгенеренную функцию вызвать дважды. Но засчитана она будет лишь одинажды. Я думал сделать так, чтобы она вообще не выполнялась более 1 раза… но имхо в запутанном коде может быть непонятно, почему так… думаю так правильнее… мало ли… циклы там…
0
вы не совсем поняли. ну грубо говоря так:
var test = new WaitSync(function () {
console.log('done');
});
setTimeout(function () {
test.wrap(fn1);
}, 100);
$.ajax('a', test.wrap(fnA));
var test = new WaitSync(function () {
console.log('done');
});
setTimeout(function () {
test.wrap(fn1);
}, 100);
$.ajax('a', test.wrap(fnA));
+1
отправилось раньше времени
вы не совсем поняли. ну грубо говоря так:
именно эта ситуация практически нереальна, но при создании, например игрушки, теоретически может случится. и что тогда если запросы a и b выполнятся раньше, чем добавится fnC?
вы не совсем поняли. ну грубо говоря так:
var test = new WaitSync(function () {
console.log('done');
});
setTimeout(function () {
$.ajax('c', test.wrap(fnC));
}, 100);
$.ajax('a', test.wrap(fnA));
$.ajax('b', test.wrap(fnB));
именно эта ситуация практически нереальна, но при создании, например игрушки, теоретически может случится. и что тогда если запросы a и b выполнятся раньше, чем добавится fnC?
+1
да, в этом случае до fnC дело может не дойти, т.к. сгенерирована она будет не сразу. Можно перестроить код слегонца…
М… ну как-то так… хотя уже попахивает чем-то путанным. Ну на подобный счет у меня другая мысль, но о ней не тут ) Могу прототип показать, если что, но там оч. сыро)
var test = new WaitSync(function () {
console.log('done');
});
setTimeout(test.wrap(function () {
$.ajax('c',
test.wrap(fnC)));
}), 100);
$.ajax('a', test.wrap(fnA));
$.ajax('b', test.wrap(fnB));
М… ну как-то так… хотя уже попахивает чем-то путанным. Ну на подобный счет у меня другая мысль, но о ней не тут ) Могу прототип показать, если что, но там оч. сыро)
0
подсветите код через:
<source lang="javascript">
// code
</source>
+1
UFO just landed and posted this here
извиняюсь, если запутал -_-.
Если вам нужен синхронный аджакс запрос, для этого есть параметр async. По умолчанию он true. Можно поставить false.
Если вам нужно что-то не только для аджакса… ждите следующего топика ;)
Если вам нужен синхронный аджакс запрос, для этого есть параметр async. По умолчанию он true. Можно поставить false.
$.ajax({
url: 'something.php',
async: false
});
Если вам нужно что-то не только для аджакса… ждите следующего топика ;)
0
Может, подскажете, как все-таки «превратить» асинхронную функцию в синхронную?
С сохранением всех преимуществ асинхронной на джаваскрипте — нельзя.
Но зачем? Достаточно научится пользоваться асинхронными функциями, и не будет таких непонятных идей
+1
UFO just landed and posted this here
Тогда что вам мешает вызвать эту синхронную функцию в callback асинхронной? Или она не имеет такой возможности?
0
UFO just landed and posted this here
То, что «выше», можно разделить на две функции и вторую вызвать как callback, вот о чём :-) Это не требует сильного изменения кода, достаточно copy&paste.
0
UFO just landed and posted this here
Вам нужно привыкнуть к идеологии Javascript :-)
Если вы контролируете код, который «выше», то можно с помощью простой, описанной мной операции, сделать его работоспособным в случае, если используемая в его середине функция асинхронна. А так как в Javascript нет «самой высокой функции» a-la main(), которая выполняется последовательно, то всегда можно переписать последовательный код в код с коллбеками. Т.е. в вашем примере придётся перейти на уровень, куда вы делаете
Могу привести пример с кодом «до» и «после», если запутанно объясняю :-)
Если вы контролируете код, который «выше», то можно с помощью простой, описанной мной операции, сделать его работоспособным в случае, если используемая в его середине функция асинхронна. А так как в Javascript нет «самой высокой функции» a-la main(), которая выполняется последовательно, то всегда можно переписать последовательный код в код с коллбеками. Т.е. в вашем примере придётся перейти на уровень, куда вы делаете
return result;и сделать подобную операцию и с ним, и так далее.
Могу привести пример с кодом «до» и «после», если запутанно объясняю :-)
-1
я согласен с Sannis. Вы смотрите на Javascript как на Асм. Но Javascript — это не Асм. Тут совершенно иная идеология и на нём нельзя писать как на асме. На самом деле единственное решение — это разобраться с асинхронными вызовами и использовать таки их.
+2
Нафиг это надо? Почему бы просто синхронно не выставить?
-3
чтобы браузер у пользователя несколько секунд висел? отличная идея)
+2
Ну… не часто нужно такое в браузере. Честно говоря, я сам предпочитаю синхронно подгружать всякие статические списки и опции.
Такое могло бы понадобиться в node.js. Там много построено на асинхронных вызовах и подобная вещь могла бы существенно упростить разработку. К тому же синхронные вызовы там как бы противоречат самой идее ноды )
Такое могло бы понадобиться в node.js. Там много построено на асинхронных вызовах и подобная вещь могла бы существенно упростить разработку. К тому же синхронные вызовы там как бы противоречат самой идее ноды )
+1
UFO just landed and posted this here
не знаю от какой библиотеки $ в примере но обычно success и error имеют разные аргументы и в таком виде wrap туда не вставишь.
0
Чем вам в данном случае Deferred не угодил? Вы же, по сути, изобрели тоже самое.
0
Deferred немного для иных целей предназначен. Он позволяет задать callback'и для текущей функии в более удобном формате (хотя с этим тоже можно поспорить, когда callback'ов много, их надо перечислять в определенном порядке и испльзоват в том же порядке… хотя я сильно не юзал его еще). Его тоже можно использовать для данной цели, но вы все равно будете каждый раз создавать отдельную функцию и развешивать ее на callback'и. Привидите пример, как вы будете использовать Deferred для подобной задачи. Думаю, премущество станет очевидным после пары строк лишнего кода =)
0
как-то
parallel([
$.get('savannah/get_prey'),
$.get('savannah/get_other_predators')
]).
next(function (results) {
console.log(results);
})
0
Я так понял вы говорите вот об этом jsDeferred, а не о dojo.Deferred
Если да, то каждая функция-аргумент должна возвращать объект Deferred (в dojo тоже). И выглядеть это будет уже по-другому
Если да, то каждая функция-аргумент должна возвращать объект Deferred (в dojo тоже). И выглядеть это будет уже по-другому
parallel([
function () {
var deferred = new Deferred();
$.get('savannah/get_prey', deferred.callback());
return deferred;
},
function () {
var d = new Deferred();
$.get('savannah/get_other_predators', d.callback());
return d;
}
]).
next(function (results) {
console.log(results);
})
0
при подключении jsdeferred.jquery.js Deferred переопределяет ajax, так что так как я написал выше — будет работать
-2
А где такое может понадобиться? Обычно то что делается двумя подряд аякс запросами лучше сделать одним, дело только за проектированием протокола.
0
Когда вообще, имхо, придётся использовать эту функцию — так это при асинхронных запросах к базе, если нам необходимо двумя и больше запросами выбрать из разных таблиц пачку данных и сгруппировать в orm.
Представим, что нам надо сделать обязательно да, обязательно асинхронных запроса к MySQL на node.js.
Один — для того, чтобы получить статью, второй — чтобы получить комменты к ней.
В одном из сообщений я велосипедил на эту тему:
get : function (fn) {
var data = {};
var set = function (key, value) {
data[key] = value;
if ('article' in data && 'comments' in data) fn(data);
};
this.getArticle(function (article) {
set('article', article);
});
this.getComments(function (comments) {
set('comments', comments);
});
},
Можно это же самое написать моим решением так:
get : function (fn) {
var process = fn.after('article', 'comments')
this.getArticle (process.article);
this.getComments(process.comments);
},
Или воспользоваться решением автора топика.
+1
В правильно спроектированной системе будут три метода — .getArticle, .getComments и .getArticleWithComments.
-2
Тогда действительно не понятно почему нельзя запросы синхронными. К сожалению не знаком с node.js и его особенностями работы с MySQL. Неужели дополнительный тред на мало-мальски нагруженном сервере даёт выигрыш в производительности?
0
TheShock зря упростил ситуацию. В реальном приложении скорее всего ситуация будет сложнее: модель может по известному только ей алгоритму определять, откуда брать данные. Простейший пример: если кроме постоянного хранилища (MySQL) используется промежуточный кеш. Тогда вполне возможна ситуация, когда одна из этих функций будет обращаться, а другая нет. Естественно, что в такой ситуации серверу лучше начать рендерить дерево комментариев, если они получены раньше, а после готовности HTML для статьи и комментариев склеивать их и отдавать клиенту. Нда, хотел как лучше объяснить, а сам приводу не самый правильный пример… Но всё же. Кроме того, текущая ситуация с Node.js говорит о том, что выгодно использовать несколько соединений с БД, так что такая ситуация вполне возможна. Node.js сам по себе однопоточный, так что на четырёхядерном сервере можно и несколько потоков для операция с БД использовать.
0
Почитал немного про node.js… Видимо я до сих пор плыву в плоскости php, где на каждый запрос к серверу работает свой воркер, когда в node.js всё вращается в одном цикле. Тогда действительно без штатных средств мультитрединга, где нагрузку распараллеливать приходится в момент запросов к бд, есть с этим определённые проблемы. Только когда на такие грабли начинаешь натыкаться уже встаёт вопрос об оправданности используемых средств в текущей задаче. Но это я так, мысли в слух…
0
Хотел написать то же самое, вы меня опередили.
Понятно, если запросы идут к двум разным ресурсам. Но если к одному — то открывать два или более соединений — неоптимально.
Понятно, если запросы идут к двум разным ресурсам. Но если к одному — то открывать два или более соединений — неоптимально.
0
Это что-то вроде github.com/creationix/step, или github.com/creationix/do, или github.com/caolan/async, или github.com/fjakobs/async.js, или github.com/creationix/conductor, или github.com/shimondoodkin/node-inflow, или github.com/willconant/flow-js, или github.com/isaacs/slide-flow-control?
+4
Да, последнее время стало модным велосипедить на эту тему. При этом все реализации в итоге не сильно друг от друга отличаются, по крайне мере на взгляд новичка.
0
Вообще-то не совсем. Вернее совсем не =) Перечисленные вами библиотеки разворачивают вложенные функции в цепь. и в частности позволяют синхронизировать некоторые вызовы. При этом как и у Deferred не совсем очевидно, какому месту соответствует какая функция.
Я не пользовался этими библиотеками. Был бы признателен, если вы приведете примеры, как выглядел бы пример с обезьянками на этих библиотеках.
Более или менее похожа вот эта:
https://github.com/isaacs/slide-flow-control/blob/master/lib/async-map.js
и flow-js эм… метод this.MULTI()
но при этом в функцию передаются уже другие аргументы.
Я не пользовался этими библиотеками. Был бы признателен, если вы приведете примеры, как выглядел бы пример с обезьянками на этих библиотеках.
Более или менее похожа вот эта:
https://github.com/isaacs/slide-flow-control/blob/master/lib/async-map.js
и flow-js эм… метод this.MULTI()
но при этом в функцию передаются уже другие аргументы.
0
Пасиб за ссылки. Я, кстати, думал создать вопрос в Q&A сначала и пособирать похожие библиотеки, но вопрос с описанием оказался размером с топик. Так что вы сэкономили мне время =)))
+1
Так это ведь и прекрасно, в этом вся соль. Из многообразия реализаций эволюция отберёт наиболее подходящие.
+1
вот такие смешные декораторы в js…
0
Извиняюсь за некропостинг, но по теме очень мало информации, поэтому предложу стандартное решение.
$.when($.ajax(...), $.ajax(...)).then(function (resp1, resp2) {
//здесь единый колбэк для всех запросов
});
0
Sign up to leave a comment.
Синхронизация асинхронных вызовов. WaitSync