2015-05-26 19 views
10

例如,有一個名爲animationComplete(來自第三方庫)變量和函數調用happenAfterAnimation在Javascript中查詢本地值的首選方法是?

一個簡單的解決方案是這樣的:

while(!animationComplete) { 
    // Do nothing 
} 
happenAfterAnimation() 

或者這樣一個更復雜的解決方案:

function tryHappenAfterAnimation() { 
    if(animationComplete) { 
    happenAfterAnimation() 
    } else { 
    setTimeout(tryHappenAfterAnimation, 100) 
    } 

} 
setTimeout(tryHappenAfterAnimation, 100) 

第一個解決方案可能有一些開銷,第二個解決方案看起來有點髒。

由於future/promise是不是在Javascript的當前版本,其方式可能是有點矯枉過正這裏.. 我只是想知道是否有這種情況的一個優雅而輕巧的方式..

沒有人有有關處理這個問題的更好方法的想法?謝謝!

+0

嘗試自定義事件或發佈/訂閱。這在這種情況下可能是理想的。 – colecmc

+0

「由於未來/承諾在當前版本的Javascript中不可用......」爲其圖書館提供期貨/承諾/事件不是該語言的任務。這是圖書館的任務。 –

回答

3

第一種方法根本不起作用。它會永遠阻止線程。

缺乏內置承諾支持並不是真正的藉口不使用承諾。如果你的圖書館給你一個事件/回調驅動的方式來等待結果(如果沒有,我會感到驚訝),那麼你應該使用一個事件或承諾。

如果不是,並且查詢變量確實是您唯一的選擇,那麼我會說您的第二種方法幾乎是唯一的選擇。

2

快速總結 - 您的第一個方法將不起作用(它將只是一個無限循環),並且輪詢機制(可以使其工作)永遠不是「首選」選擇。

Javascript是單線程的(有些例外,如webWorkers,但它們不適用於此),只要你的while循環運行,沒有其他的JS可以運行,可能會改變animationComplete的值,所以你會有一個永遠不會完成的無限循環(最終瀏覽器會抱怨JS線程沒有完成並且提供給用戶停止腳本的機會)。

知道動畫何時完成的正確方法是使用回調完成動畫。如果您使用的是jQuery,那麼所有的jQuery動畫都有一個完成回調,您可以傳遞它,並在動畫完成時調用它。然後,您在回調函數中將動畫後發生的代碼放入。

如果您使用的是CSS3動畫,那麼您可以註冊一個事件處理程序來處理transitionend事件,並在動畫完成時以這種方式獲取回調。

如果您確實想輪詢變量的值,那麼使用計時器輪詢它將是一個合適的選擇,因爲這允許其他代碼運行,實際上可以更改變量。

我應該補充說,像這樣的輪詢很少是最好的設計選擇。如果它是一個動畫,那麼你只是想在動畫上使用一個完成事件,所以不需要輪詢。如果出於某種原因,您正在使用一個沒有內置完成事件的動畫函數,那麼可能需要修改該代碼以包含這樣的回調,因爲它始終是可能的,並且顯然是有用的。


對於我們提供更詳細的建議,我們需要更多地瞭解動畫代碼以及您正在嘗試做什麼。正如我之前所說的,所有的jQuery動畫都爲完成通知提供了承諾和回調支持(你沒有標記問題,jQuery就是我提到的原因)。

在任何接口中缺少承諾並不是不使用完成回調的原因,因此事實在這裏沒有真正的相關性,並且任何給定的函數也可以被承諾(如果承諾是簡單的回調,則轉換爲承諾接口)與異步事件交互的理想方式。

1

以下是基於Promises的方法。以下實施定期輪詢和超時。

var Promise = require('bluebird'); 

/** 
* Periodically poll a signal function until either it returns true or a timeout is reached. 
* 
* @param signal function that returns true when the polled operation is complete 
* @param interval time interval between polls in milliseconds 
* @param timeout period of time before giving up on polling 
* @returns true if the signal function returned true, false if the operation timed out 
*/ 
function poll(signal, interval, timeout) { 
    function pollRecursive() { 
     return signal() ? Promise.resolve(true) : Promise.delay(interval).then(pollRecursive); 
    } 

    return pollRecursive() 
     .cancellable() 
     .timeout(timeout) 
     .catch(Promise.TimeoutError, Promise.CancellationError,function() { 
      return false; 
     }); 
} 

你這樣稱呼它。

poll(animationComplete, pollingInterval, timeout) 
    .then(function(complete) { 
     if (complete) 
      happenAfterAnimation(); 
    } 
); 

請參閱Javascript polling with promises

相關問題