Как мне вызвать 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 вы можете указать функцию для выполнения после определенного тайм-аута (в миллисекундах). Это может, по сути, заставить синхронные функции вести себя асинхронно.

если мы имеем 3 одновременных функции, то мы можем исполнить их асинхронно используя


этот ответ использует promises, функция JavaScript ECMAScript 6 стандартные. Если ваша целевая платформа не поддерживает promises, polyfill оно с 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
});

на then метод выполняется, как только Promise закончил. Как правило, возвращаемое значение function перешло к then передается следующему в результате.

но если Promise возвращается, следующий then функция ждет, пока Promise закончил выполнение и получает его результаты (значение, которое передается в fulfill).


похоже, вы не полностью оцениваете разницу между синхронно и асинхронные выполнение функции.

код, который вы предоставили в своем обновлении тут выполняет каждую из ваших функций обратного вызова, которые, в свою очередь, немедленно запускают анимацию. Анимация, однако, выполнить asyncronously. Он работает следующим образом:

  1. выполните шаг в анимация
  2. вызов setTimeout С функцией, содержащей следующий шаг анимации и задержку
  3. проходит некоторое время
  4. обратный вызов дан setTimeout выполняет
  5. вернитесь к шагу 1

это продолжается до завершения последнего шага анимации. Тем временем, ваши синхронные функции давно завершены. Другими словами, ваш призыв к


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

function fone(callback){
...do something...
callback.apply(this,[]);

}

function ftwo(callback){
...do something...
callback.apply(this,[]);
}

тогда использование будет похоже:

fone(function(){
  ftwo(function(){
   ..ftwo done...
  })
});

Я считаю асинхронные библиотека предоставит вам очень элегантный способ, чтобы сделать это. В то время как обещания и обратные вызовы могут стать немного трудными для жонглирования, async может дать аккуратные шаблоны для оптимизации вашего мыслительного процесса. Чтобы запускать функции последовательно, вам нужно будет поместить их в async водопад. На асинхронном языке каждая функция называется 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 global для доступа к нему изнутри .тогда

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

    one(some_value).then(function(return_of_one){
       two(return_of_one).then(function(return_of_two){
          three(return_of_two);
       });
    });

Я использую функцию "waitUntil" на основе setTimeout javascript

/*
    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);

Примечания

дата вызывает грубый тайм-аут оценки. Для большей точности переключитесь на такие функции, как console.время.)( Обратите внимание, что Date предлагает большую кросс-браузерную и устаревшую поддержку. Если вам не нужны точные измерения миллисекунды; не беспокойтесь, или, альтернативно, оберните его и предложите консоль.time () когда браузер поддерживает его