Как я должен вызвать 3 функции, чтобы выполнить их одну за другой?
если мне нужно вызвать эту функцию одну за другой,
$('#art1').animate({'width':'1000px'},1000);
$('#art2').animate({'width':'1000px'},1000);
$('#art3').animate({'width':'1000px'},1000);
Я знаю, что в jQuery я мог бы сделать что-то вроде:
$('#art1').animate({'width':'1000px'},1000,'linear',function(){
$('#art2').animate({'width':'1000px'},1000,'linear',function(){
$('#art3').animate({'width':'1000px'},1000);
});
});
но, предположим, что я не использую jQuery и я хочу назвать:
some_3secs_function(some_value);
some_5secs_function(some_value);
some_8secs_function(some_value);
как я должен вызвать эту функцию, чтобы выполнить some_3secs_function, и после этого вызов заканчивается, а затем выполнить some_5secs_function и после этого вызова заканчивается, а затем позвоните some_8secs_function?
обновление:
это еще не рабочий:
(function(callback){
$('#art1').animate({'width':'1000px'},1000);
callback();
})((function(callback2){
$('#art2').animate({'width':'1000px'},1000);
callback2();
})(function(){
$('#art3').animate({'width':'1000px'},1000);
}));
три анимации начинаются одновременно
где моя ошибка.
10 ответов:
в Javascript есть синхронно и асинхронные функции.
Синхронные Функции
большинство функций в Javascript являются синхронными. Если бы вы вызывали несколько синхронных функций подряд
doSomething(); doSomethingElse(); doSomethingUsefulThisTime();они будут исполнять по порядку.
doSomethingElseне начнется, покаdoSomethingзавершено.doSomethingUsefulThisTime, в свою очередь, не начнется доdoSomethingElseзавершено.асинхронный Функции
асинхронные функции, однако, не будут ждать друг друга. Давайте посмотрим на тот же пример кода, который мы имели выше, на этот раз предполагая, что функции являются асинхронными
doSomething(); doSomethingElse(); doSomethingUsefulThisTime();функции будут инициализированы по порядку, но все они будут выполняться примерно в одно и то же время. Вы не можете последовательно предсказать, какой из них завершится первым: тот, который займет самое короткое время для выполнения, завершится первым.
но иногда вы хотите, чтобы асинхронные функции выполнялись по порядку, а иногда вы хотите, чтобы синхронные функции выполнялись асинхронно. К счастью, это возможно с обратными вызовами и таймаутами, соответственно.
обратные вызовы
предположим, что у нас есть три асинхронные функции, которые мы хотим выполнить по порядку,
some_3secs_function,some_5secs_functionиsome_8secs_function.поскольку функции могут быть переданы в качестве аргументов в JavaScript, вы можете передать функция как обратный вызов для выполнения после завершения функции.
если мы создадим такие функции
function some_3secs_function(value, callback){ //do stuff callback(); }тогда вы можете позвонить тогда по порядку, Вот так:
some_3secs_function(some_value, function() { some_5secs_function(other_value, function() { some_8secs_function(third_value, function() { //All three functions have completed, in order. }); }); });ожидания
в Javascript вы можете указать функцию для выполнения после определенного тайм-аута (в миллисекундах). Это может, по сути, заставить синхронные функции вести себя асинхронно.
если у нас есть три синхронные функции, мы можем их исполнить асинхронно используя
этот ответ использует
promisesфункция JavaScript иECMAScript 6стандартные. Если ваша целевая платформа не поддерживаетpromises, заполните его с PromiseJs.посмотри на мой ответ здесь подождите, пока функция с анимацией не будет завершена до запуска другой функции если вы хотите использовать
jQueryанимация.вот как будет выглядеть ваш код с
ES6 PromisesиjQuery animations.Promise.resolve($('#art1').animate({ 'width': '1000px' }, 1000).promise()).then(function(){ return Promise.resolve($('#art2').animate({ 'width': '1000px' }, 1000).promise()); }).then(function(){ return Promise.resolve($('#art3').animate({ 'width': '1000px' }, 1000).promise()); });обычные методы также могут быть обернуты в
Promises.new Promise(function(fulfill, reject){ //do something for 5 seconds fulfill(result); }).then(function(result){ return new Promise(function(fulfill, reject){ //do something for 5 seconds fulfill(result); }); }).then(function(result){ return new Promise(function(fulfill, reject){ //do something for 8 seconds fulfill(result); }); }).then(function(result){ //do something with the result });The
thenметод выполняется, как толькоPromiseзакончил. Как правило, возвращаемое значениеfunctionперешло кthenпередается на следующий в результате.но если a
Promiseвозвращается, следующийthenфункция ждет, покаPromiseзакончил выполнение и получает его результаты (значение, которое передается вfulfill).
похоже, что вы не полностью осознаете разницу между синхронно и асинхронные выполнение функции.
код, который вы указали в своем обновлении тут выполняет каждую из ваших функций обратного вызова, которые в свою очередь немедленно запускают анимацию. Анимации, однако, выполнить asyncronously. Это работает следующим образом:
- выполните шаг в анимация
- вызов
setTimeoutС функцией, содержащей следующий шаг анимации и задержку- проходит некоторое время
- обратный вызов дан
setTimeoutвыполняет- вернитесь к шагу 1
это продолжается до завершения последнего шага в анимации. Тем временем, ваши синхронные функции уже давно завершены. Другими словами, ваш звонок в
ваши функции должны принимать функцию обратного вызова, которая вызывается, когда она заканчивается.
function fone(callback){ ...do something... callback.apply(this,[]); } function ftwo(callback){ ...do something... callback.apply(this,[]); }тогда использование будет похоже:
fone(function(){ ftwo(function(){ ..ftwo done... }) });
Я считаю асинхронные библиотека предоставит вам очень элегантный способ, чтобы сделать это. В то время как обещания и обратные вызовы могут стать немного трудными для жонглирования, асинхронность может дать аккуратные шаблоны для оптимизации вашего мыслительного процесса. Чтобы запускать функции последовательно, вам нужно будет поместить их в асинхронный водопад. В асинхронном жаргоне каждая функция называется
taskэто требует некоторых аргументов иcallback; которая является следующей функцией в последовательности. Базовая структура будет выглядеть что-то вроде:async.waterfall([ // A list of functions function(callback){ // Function no. 1 in sequence callback(null, arg); }, function(arg, callback){ // Function no. 2 in sequence callback(null); } ], function(err, results){ // Optional final callback will get results for all prior functions });Я только что попытался кратко объяснить структуру здесь. Читайте через водопад руководство для получения дополнительной информации, это очень хорошо написано.
asec=1000; setTimeout('some_3secs_function("somevalue")',asec*3); setTimeout('some_5secs_function("somevalue")',asec*5); setTimeout('some_8secs_function("somevalue")',asec*8);Я не буду вдаваться в глубокое обсуждение метода setTimeout, но:
- в этом случае я добавил код для выполнения в виде строки. это самый простой способ передать var в вашу функцию setTimeout-ed, но пуристы будут жаловаться.
- вы также можете передать имя функции без кавычек, но никакая переменная не может быть передана.
- ваш код не ждет запуска setTimeout.
- это может быть трудно получить вашу голову вокруг во - первых: из-за предыдущего пункта, если вы передадите переменную из своей вызывающей функции, эта переменная больше не будет существовать к моменту срабатывания тайм-аута-вызывающая функция будет выполнена, и она исчезнет.
- Я, как известно, использовать анонимные функции, чтобы обойти все это, но там вполне может быть лучший способ,
Так как вы пометили его javascript, я бы пошел с таймером управления, так как ваши имена функций 3, 5 и 8 секунд. Итак, запустите таймер, через 3 секунды, вызовите первый, через 5 секунд вызовите второй, через 8 секунд вызовите третий, а затем, когда это будет сделано, остановите таймер.
обычно в Javascript то, что у вас есть, правильно для функций, работающих один за другим, но поскольку похоже, что вы пытаетесь сделать временную анимацию, таймер будет вашим лучшим выбором.
//sample01 (function(_){_[0]()})([ function(){$('#art1').animate({'width':'10px'},100,this[1].bind(this))}, function(){$('#art2').animate({'width':'10px'},100,this[2].bind(this))}, function(){$('#art3').animate({'width':'10px'},100)}, ]) //sample02 (function(_){_.next=function(){_[++_.i].apply(_,arguments)},_[_.i=0]()})([ function(){$('#art1').animate({'width':'10px'},100,this.next)}, function(){$('#art2').animate({'width':'10px'},100,this.next)}, function(){$('#art3').animate({'width':'10px'},100)}, ]); //sample03 (function(_){_.next=function(){return _[++_.i].bind(_)},_[_.i=0]()})([ function(){$('#art1').animate({'width':'10px'},100,this.next())}, function(){$('#art2').animate({'width':'10px'},100,this.next())}, function(){$('#art3').animate({'width':'10px'},100)}, ]);
вы также можете использовать обещания таким образом:
some_3secs_function(this.some_value).then(function(){ some_5secs_function(this.some_other_value).then(function(){ some_8secs_function(this.some_other_other_value); }); });вы должны были бы сделать
some_valueглобальный для того, чтобы получить доступ к нему изнутри .тогдакроме того, из внешней функции вы можете вернуть значение, которое будет использовать внутренняя функция, например:
one(some_value).then(function(return_of_one){ two(return_of_one).then(function(return_of_two){ three(return_of_two); }); });
Я использую функцию 'waitUntil' на основе javascript setTimeout
/* funcCond : function to call to check whether a condition is true readyAction : function to call when the condition was true checkInterval : interval to poll <optional> timeout : timeout until the setTimeout should stop polling (not 100% accurate. It was accurate enough for my code, but if you need exact milliseconds, please refrain from using Date <optional> timeoutfunc : function to call on timeout <optional> */ function waitUntil(funcCond, readyAction, checkInterval, timeout, timeoutfunc) { if (checkInterval == null) { checkInterval = 100; // checkinterval of 100ms by default } var start = +new Date(); // use the + to convert it to a number immediatly if (timeout == null) { timeout = Number.POSITIVE_INFINITY; // no timeout by default } var checkFunc = function() { var end = +new Date(); // rough timeout estimations by default if (end-start > timeout) { if (timeoutfunc){ // if timeout function was defined timeoutfunc(); // call timeout function } } else { if(funcCond()) { // if condition was met readyAction(); // perform ready action function } else { setTimeout(checkFunc, checkInterval); // else re-iterate } } }; checkFunc(); // start check function initially };это будет отлично работать, если ваши функции задают определенное условие true, которое вы сможете опросить. Кроме того, он поставляется с тайм-аутами, которые предлагают вам альтернативы в случае, если ваша функция не смогла что-то сделать (даже в пределах временного диапазона. Подумайте о обратной связи с пользователем!)
например
doSomething(); waitUntil(function() { return doSomething_value===1;}, doSomethingElse); waitUntil(function() { return doSomethingElse_value===1;}, doSomethingUseful);Примечания
дата вызывает грубый тайм-аут оценки. Для большей точности переключитесь на такие функции, как консоль.время.)( Обратите внимание, что Date предлагает большую кросс-браузерную и устаревшую поддержку. Если вам не нужны точные измерения миллисекунды; не беспокойтесь, или, альтернативно, оберните его и предложите консоль.время (), когда браузер поддерживает его
Comments