2013-07-10 117 views
12

我需要在1秒的延遲時間內執行3個函數。嵌套setTimeout替代?

爲簡單起見,這些功能是:

console.log('1'); 
console.log('2'); 
console.log('3'); 

我可以這樣做:(非常難看)

console.log('1') 
setTimeout(function() { 
    setTimeout(function() { 
     console.log('2') 
     setTimeout(function() { 
      console.log('3') 

     }, 1000) 
    }, 1000) 

}, 1000) 

或者我可以創建功能的array和使用setIntervalglobal計數器。

有沒有優雅這樣做的方法? (p.s.函數no.2不依賴函數編號1 ...因此 - 每秒執行下一個函數)。

+0

如果他們沒有依賴性等,爲什麼他們需要在不同的時間執行? (只要確保它是必需的)你可以簡單地使用3個超時seperatly,一個在1秒,第二個在2秒等等... – Salketer

+1

使用setTimeout與循環... for(...){setTimeout(function() {},1000 * index); }或類似 – Givi

+0

@Salketer網絡壓力可能?爲什麼這很重要? –

回答

13

您可以使用像這樣用setTimeout

var funcs = [func1, func2, func3], 
    i = 0; 

function callFuncs() { 
    funcs[i++](); 
    if (i < funcs.length) setTimeout(callFuncs, 1000); 
} 
setTimeout(callFuncs, 1000); //delay start 1 sec. 

或只是()直接調用callFuncs開始。

更新

setInterval方法(注意調用堆棧的風險):

var funcs = [func1, func2, func3], 
    i = 0, 
    timer = setInterval(callFuncs, 1000); 

function callFuncs() { 
    funcs[i++](); 
    if (i === funcs.length) clearInterval(timer); 
} 
+1

@RoyiNamir你爲什麼需要將指數乘以1000?... – Snuffleupagus

+0

我的不好。刪除。 –

+0

這是我想到的(已經在我的問題中提到過) - 但我想知道是否有更多的解決方案.... –

2
setTimeout(function(){console.log('1')}, 1000); 
setTimeout(function(){console.log('2')}, 2000); 
setTimeout(function(){console.log('3')}, 3000); 
9

假設你在一個現代瀏覽器上運行,或加入了對陣列支持。這個圖很簡潔:

[func1, func2, func3].map(function (fun, index) { 
    setTimeout(fun, 1000 + index * 1000); 
} 
1

我認爲最簡單的方法是在函數中創建一些閉包。
首先我會記得你對使用setInterval有很大興趣,因爲setTimeout的開銷可能會觸發10ms的目標。所以特別是如果使用短時間(< 50ms)時間間隔,更喜歡setInterval。 所以我們需要存儲函數數組,最近執行的函數的索引以及間隔引用來停止調用。

function chainLaunch(funcArray, time_ms) { 
    if (!funcArray || !funcArray.length) return; 
    var fi = 0; // function index 
    var callFunction = function() { 
     funcArray[fi++](); 
     if (fi==funcArray.length) 
       clearInterval(chainInterval); 
    } ; 
    var chainInterval = setInterval(callFunction, time_ms); 
} 

的Rq:您可能希望函數數組(funcArray = funcArray.slice(0);
複製RQ2:您可能數組
RQ3內要循環:你可能要接受其它附加參數chainlaunch。與var funcArgs = arguments.slice(3);找回它們並使用應用的功能:funcArray[fi++].apply(this,funcArgs);

反正下面的測試原理:

var f1 = function() { console.log('1'); }; 
var f2 = function() { console.log('2'); }; 
var f3 = function() { console.log('3'); }; 

var fArr = [f1, f2, f3]; 

chainLaunch(fArr, 1000); 

,你可以在這個小提琴看到:http://jsfiddle.net/F9UJv/1/ (打開控制檯)

0

有這裏有兩種方法。一個使用setTimeout,另一個使用setInterval。我認爲第一個更好。

for(var i = 1; i++; i<=3) { 
 
    setTimeout(function() { 
 
     console.log(i); 
 
    }, 1000*i); 
 
} 
 
// second choice: 
 
var i = 0; 
 
var nt = setInterval(function() { 
 
     if(i == 0) return i++; 
 
     console.log(i++); 
 
     if(i>=3) clearInterval(nt); 
 
    }, 1000);

1

有在ES6一種新型的函數聲明稱爲發生器(a.k.a的ECMAScript 6,ES2015)。這對於這種情況非常有用,並使異步代碼看起來同步。 es6是2015年最新的JavaScript標準。它適用於現代瀏覽器,但您可以使用Babel及其javascript填充,現在即使在舊版瀏覽器中也可以使用生成器。

Here是關於生成器的教程。

下面的函數myDelayedMessages是一個生成器的例子。 Run是一個輔助函數,它接受一個它調用的生成器函數,並提供一個函數來推進生成器,作爲它所調用的生成器函數的第一個參數。

function delay(time, callback) { 
 
     setTimeout(function() { 
 
     callback(); 
 
     }, time); 
 
} 
 

 
function run(generatorFunction) { 
 
    var generatorItr = generatorFunction(resume); 
 
    function resume(callbackValue) { 
 
    generatorItr.next(callbackValue); 
 
    } 
 
    generatorItr.next() 
 
} 
 

 
run(function* myDelayedMessages(resume) { 
 
    for(var i = 1; i <= 3; ++i) { 
 
    yield delay(1000, resume); 
 
    console.log(i); 
 
    } 
 
});

這是其類似於上面的教程的最後概述的代碼的概述。

  1. run需要我們的發電機,並創建一個恢復功能。運行會創建一個 生成器 - 迭代器對象(您接下來要調用的對象),並提供 恢復。
  2. 然後它將發生器迭代器向前推進一步,以將所有東西都踢出去。
  3. 我們的發電機遇到第一個產量聲明 並調用延遲。
  4. 然後發電機暫停。
  5. 延遲1000毫秒後完成並調用繼續。
  6. 恢復告訴我們的發電機前進一步。
  7. 我們的發電機從它產生了在然後console.logs i中的點,這是1繼續,然後繼續循環
  8. 我們發生器遇到第二呼叫,以產生, 呼叫延遲和再次暫停。
  9. 延遲等待1000毫秒,最終調用resume resume回調 。恢復提前發電機。
  10. 我們的發電機繼續從它產生的地點繼續console.logs我,這是2,然後繼續循環。
  11. 延遲等待1000毫秒,最終調用resume resume回調 。恢復提前發電機。
  12. 我們的發電機繼續從它產生的地點繼續console.logs我,這是3,然後繼續和循環完成。
  13. 有沒有更多的調用產量,發電機完成執行。