我应该怎样调用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和AFTER那个调用结束,然后调用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); })); 

三个animation同时开始

我的错误在哪里?

在Javascript中,有同步asynchronousfunction。

同步function

Javascript中的大部分函数都是同步的。 如果你要连续调用几个同步函数

 doSomething(); doSomethingElse(); doSomethingUsefulThisTime(); 

他们将按顺序执行。 doSomethingElsedoSomething完成之前不会启动。 doSomethingUsefulThisTime ,反过来,将不会开始,直到doSomethingElse完成。

asynchronous函数

asynchronous函数,但是,不会等待对方。 让我们看看上面的代码示例,这次假设这些函数是asynchronous的

 doSomething(); doSomethingElse(); doSomethingUsefulThisTime(); 

函数将按顺序初始化,但它们都将大致同时执行。 你不能一致地预测哪一个会先完成:恰好花费最短时间执行的那个会先完成。

但是有时候,你需要按顺序执行asynchronous的函数,有时你需要asynchronous执行的函数来asynchronous执行。 幸运的是,这可能分别与callback和超时。

callback

假设我们有三个some_3secs_function顺序执行的asynchronous函数, some_3secs_functionsome_5secs_functionsome_8secs_function

由于函数可以在Javascript中作为parameter passing,因此可以在函数完成后将函数作为callback函数执行。

如果我们创build这样的function

 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中,你可以告诉一个函数执行一定的超时(以毫秒为单位)。 实际上,这可以使同步函数asynchronous行为。

如果我们有三个同步函数,我们可以使用setTimeout函数asynchronous执行它们。

 setTimeout(doSomething, 10); setTimeout(doSomethingElse, 10); setTimeout(doSomethingUsefulThisTime, 10); 

但是,这有点丑陋,违反了DRY原则[维基百科] 。 我们可以通过创build一个接受一系列函数和超时的函数来清理这个问题。

 function executeAsynchronously(functions, timeout) { for(var i = 0; i < functions.length; i++) { setTimeout(functions[i], timeout); } } 

这可以这样调用:

 executeAsynchronously( [doSomething, doSomethingElse, doSomethingUsefulThisTime], 10); 

总而言之,如果您有要同步执行的asynchronous函数,请使用callback函数,并且如果您有要asynchronous执行的同步函数,请使用超时。

这听起来像你不完全理解同步asynchronous函数执行的区别。

您在更新中提供的代码会立即执行您的每个callback函数,然后立即启动一个animation。 然而,animation执行asynchronous 。 它是这样工作的:

  1. 在animation中执行一个步骤
  2. 用包含下一个animation步骤和延迟的函数调用setTimeout
  3. 一段时间过去了
  4. setTimeout的callback执行
  5. 回到步骤1

这一直持续到animation的最后一步完成。 同时,你的同步function早已完成。 换句话说,你对animate函数的调用并不需要3秒。 效果是模拟延迟和callback。

你需要的是一个队列 。 在内部,jQuery排队animation,只有在相应的animation完成后才执行callback。 如果您的callback开始另一个animation,效果是,他们顺序执行。

在最简单的情况下,这相当于以下内容:

 window.setTimeout(function() { alert("!"); // set another timeout once the first completes window.setTimeout(function() { alert("!!"); }, 1000); }, 3000); // longer, but first 

这是一个通用的asynchronous循环函数。 它将按顺序调用给定的函数,等待每个指定的秒数。

 function loop() { var args = arguments; if (args.length <= 0) return; (function chain(i) { if (i >= args.length || typeof args[i] !== 'function') return; window.setTimeout(function() { args[i](); chain(i + 1); }, 2000); })(0); } 

用法:

 loop( function() { alert("sam"); }, function() { alert("sue"); }); 

你显然可以修改这个来进行可configuration的等待时间,或者立即执行第一个函数,或者当链中的函数返回false或者在指定的上下文中apply函数或者其他任何你可能需要的函数时停止执行。

这个答案使用了ECMAScript 6标准的JavaScript特性promises 。 如果您的目标平台不支持promises ,请使用PromiseJs进行填充 。

看看我的答案在这里等到有animation的函数完成,直到运行另一个函数,如果你想使用jQueryanimation。

这里是你的代码看起来像ES6 PromisesjQuery 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 }); 

Promise完成后立即执行该方法。 正常情况下,传递给它的function的返回值作为结果传递给下一个function

但是,如果Promise被返回,那么下一个函数将等待Promise完成执行并接收它的结果(传递的值)。

你的函数应该有一个callback函数,当它完成时被调用。

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

那么用法就像

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

我相信asynchronous库将为您提供一个非常优雅的方式来做到这一点。 虽然承诺和callback可以有点难以兼顾,asynchronous可以给整洁的模式,以简化你的思维过程。 要以串行方式运行函数,您需要将它们放在asynchronous瀑布中 。 在asynchronous术语中,每个函数被称为一个task ,需要一些参数和一个callback ; 这是序列中的下一个function。 基本结构看起来像这样:

 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,但是:

  • 在这种情况下,我已经添加了代码来执行一个string。 这是将var传递给setTimeout-ed函数的最简单的方法,但纯粹主义者会抱怨。
  • 您也可以传递不带引号的函数名称,但不能传递variables。
  • 你的代码不会等待setTimeout触发。
  • 这个很难让你头脑发热:因为以前的观点,如果你从你的调用函数传递一个variables,这个variables在超时触发时就不会再存在了 – 调用函数将会执行,瓦尔斯消失了。
  • 我已经知道使用匿名函数来解决所有这些,但是可能有更好的方法,

既然你用javascript标记了它,我会去用一个计时器控件,因为你的函数名是3,5和8秒。 所以启动你的计时器,3秒钟进入,第一次呼叫,第二秒钟5秒钟,第三秒钟呼叫8秒钟,然​​后停止计时器。

通常在Javascript中,你所拥有的function是一个接一个地运行是正确的,但是因为它看起来像你正在尝试做定时animation,所以定时器将是你最好的select。

你也可以用这种方式使用promise:

  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); }); }); 
 //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)}, ]); 

我使用基于javascript的setTimeout的'waitUntil'函数

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

如果你的函数将某些条件设置为真,你就可以进行轮询。 另外它还有超时function,当你的function不能做某些事情(甚至在时间范围内)时,它提供了另外的select,想想用户的反馈!

例如

 doSomething(); waitUntil(function() { return doSomething_value===1;}, doSomethingElse); waitUntil(function() { return doSomethingElse_value===1;}, doSomethingUseful); 

笔记

date导致粗略的超时估计。 为了获得更高的精确度,请切换到诸如console.time()之类的函数。 请注意date提供了更大的跨浏览器和传统的支持。 如果你不需要精确的毫秒测量, 不要打扰,或者换一种方式来包装它,并在浏览器支持时提供console.time()