[英]Run code after some time has passed or a condition is met
什么是編寫代碼的最佳和最干燥的方法,可以在經過一段時間(例如 5 秒)或滿足某些條件(例如bool = true
)時執行 -以先到者為准。 從腳本第一次運行開始計算五秒,boolean 是一個全局變量,由另一個 function 更改。 我認為您不能將超時和布爾檢查結合在一個語句中,但另一種好方法也很好。
偽代碼:
if (bool = true OR timePassed = 5000):
runCode()
如果在達到時間限制之前調用該函數,則可以設置超時並取消它。
var timeout = setTimeout(function() {
runCode();
}, 5000);
function runCode() {
clearTimeout(timeout);
...
}
編輯:現在我想到了,在這個例子中設置超時的更好方法是
var timeout = setTimeout(runCode, 5000);
這些答案實際上都沒有提供問題的完整答案,即首先沒有實現的最后一個 - 或者最終的代碼運行兩次。
你需要一個計時器和一個條件(如其他答案所示,但未能在一個整體中合並)。
var done = false;
var thisTimeout = setTimeout(function() {
myFunction();
}, 1000);
if ((someCondition) && !done) {
myFunction();
}
function myFunction() {
clearTimeout(thisTimeout);
done = true;
// Do stuff
}
以下代碼使用兩個全局變量condition
和seconds
。 計時器每秒運行一次,如果condition
不為true
或seconds
不超過4,則seconds
增加1。
condition = false // global
seconds = 0 // global
var timer = setInterval(function() {
if (condition || seconds > 4) {
clearInterval(timer)
}
seconds+=1;
}, 1000);
window.onload = function(){
var timer = setTimeout(RunCode, 5000);
function RunCode(){
//do something
//RunCode() already done and we don't want to run it second time
element.onevent = function(){};
}
//pseudo code
element.onevent = function(){
clearTimeout(timer);
RunCode();
}
//possibly more event handlers with similar logic
}
為了解決android中的這類問題,我想出了一個構造調用者Barrier。 它在滿足條件或超過 SLA(您想要的超時)時執行代碼。
為了滿足您的需求,請執行以下操作,
Barrier b = Barrier.with(() -> false).withSLA(5000, true).startSLA();
代碼庫中會有一個點,您要檢查是否滿足某些條件? 例如,如果您想檢查 API 調用是否完成,請將其放在其響應代碼中。
b.strike()
下面是實現,
/**
* Barrier creates a condition based barrier, which prevents a piece of code from being executed
* till a condition represented by {@link Condition} becomes true. It has an optional SLA
* that executes the code, if that SLA(in millis) expires only if execution did not take place due
* to the condition getting satisfied. It works in "which ever happens first" basis.
* If the condition gets satisfied first, then SLA will be ignored. And if SLA expires and then the condition
* gets satisfied after that then only SLA expiration execution will take place.
* Once a barrier is broken and {@link BarrierCode} is executed, it will not execute again for the
* same barrier instance. Barrier is a one time use class.
*/
public final class Barrier {
public static final String EXECUTED_DUE_TO_SLA = "sla";
public static final String EXECUTED_DUE_TO_CONDITION = "condition";
private static final String TAG = Barrier.class.getSimpleName();
// This is only there for tests, as there has to be a way to know the type of execution happened
// Whether it was due to SLA breach or condition getting satisfied.
@VisibleForTesting
AtomicReference<String> mExecutionMechanism = new AtomicReference<>(null);
private final WeakReference<Condition> mCondition;
private final AtomicBoolean mHasExecuted;
private final AtomicBoolean mSlaStarted = new AtomicBoolean(false);
private long mSLA = -1;
private BarrierCode mCode;
private boolean mShouldPostOnMainThread;
private Barrier(WeakReference<Condition> condition) {
this.mCondition = condition;
mHasExecuted = new AtomicBoolean(false);
}
/**
* Creates a Barrier object with a given condition.
*
* @param condition condition used to break the barrier.
* @return Barrier object
*/
public static Barrier with(@NonNull Condition condition) {
WeakReference<Condition> temp = new WeakReference<>(condition);
return new Barrier(temp);
}
public boolean hasBarrierFinishedExecution() {
return mHasExecuted.get();
}
/**
* Takes the code that needs to be executed when the barrier breaks due to condition getting
* satisfied or SLA expiration in "which ever happens first" fashion.
*
* @param code Barrier code
* @return Barrier object with barrier code defined
*/
public Barrier runOnBreak(@NonNull BarrierCode code) {
this.mCode = code;
return this;
}
/**
* Defines the optional SLA for the execution. If the condition does not get satisfied till the SLA
* reaches, the defined barrier code will get executed anyways. It takes a parameter,
* shouldPostOnMainThread that dictates on which thread code gets executed. If this method is called
* multiple times on a barrier object before calling {@link Barrier#startSLA()} only the last call
* is honoured. Calling this after {@link Barrier#startSLA()} has no effect.
* Note: It is important to call {@link Barrier#startSLA()} after calling this method that
* triggers the operation of posting the BarrierCode on the required thread. Not calling startSLA()
* will ignore SLA parameter and nothing will happen in relation to SLA.
*
* @param slaInMillis SLA in milli seconds.
* @param shouldPostOnMainThread should the Barrier code be posted on main thread.
* @return Barrier object after capturing SLA.
*/
public Barrier withSLA(long slaInMillis, boolean shouldPostOnMainThread) {
// When SLA is not defined.
if (slaInMillis <= 0) {
throw new IllegalArgumentException("SLA should not be 0 or less than 0");
}
this.mSLA = slaInMillis;
this.mShouldPostOnMainThread = shouldPostOnMainThread;
return this;
}
/**
* This is point from where the SLA counting starts. This call is important if the SLA needs to work.
* This can be called from a different place where the barrier is created. Calling this method multiple times
* has no effect. Only the first call is honoured.
*
* @return Barrier
*/
public Barrier startSLA() {
if (mCode == null) {
throw new IllegalStateException("BarrierCode not defined in the barrier.");
}
if (mSLA == -1) {
throw new IllegalStateException("SLA is not defined and startSLA() called, use withSLA() first.");
}
boolean willStartSLAFromHere = mSlaStarted.compareAndSet(false, true);
if (willStartSLAFromHere) {
if (mShouldPostOnMainThread) {
Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.postDelayed(this::tryExecute, mSLA);
} else {
TaskUtilities.runOnBackgroundThreadWithDelay(this::tryExecute, CancellationToken.NONE, mSLA);
}
}
return this;
}
private void tryExecute() {
boolean willExecute = mHasExecuted.compareAndSet(false, true);
if (willExecute) {
mExecutionMechanism.compareAndSet(null, EXECUTED_DUE_TO_SLA);
Log.d(TAG, "Barrier condition did not become true, started executing due to SLA");
mCode.invoke();
} else {
Log.d(TAG, "Barrier code already executed due to the condition becoming true. SLA will be ignored.");
}
}
/**
* Barriers can only be broken if we strike/flick them enough no of times. This needs to installed in
* the execution path where the condition needs to be evaluated.
* Once a barrier is broken and {@link BarrierCode} is executed, it will never execute again
* for the same barrier instance.
*/
public void strike() {
if (mCode == null) {
throw new IllegalStateException("Barrier cannot be created without a barrier code, "
+ "Try using runOnBreak() to pass a code for the barrier.");
}
if (mCondition.get() != null && !mHasExecuted.get() && mCondition.get().evaluate()) {
boolean willExecute = mHasExecuted.compareAndSet(false, true);
if (willExecute) {
mExecutionMechanism.compareAndSet(null, EXECUTED_DUE_TO_CONDITION);
mCode.invoke();
Log.d(TAG, "Barrier code started executing due to the condition getting satisfied.");
} else {
Log.d(TAG, "Barrier code already executed due to an smaller SLA");
}
}
}
/**
* Usually the code instance is retained till the barrier instance is in the memory.
* Use clear if the barrier instance has a wider scope and we want to clear the code.
* After calling this method, all invocations of strike will throw IllegalStateException
*/
public void clear() {
mCode = null;
}
/**
* Piece of code that needs to be executed once the barrier is broken due to the
* {@link Condition} getting satisfied or SLA time is expired!
*/
public interface BarrierCode {
void invoke();
}
/**
* Represents the condition that should break the Barrier.
*/
public interface Condition {
/**
* Implementors should override this method to implement their barrier condition.
* {@link Barrier} internally calls evaluate() every time {@link Barrier#strike()} is
* called. Once the condition becomes true, if executes the codes represented by
* {@link BarrierCode}
*
* @return true, if the condition is satisfied, false otherwise.
*/
boolean evaluate();
}
}
是不是setTimeout你在找什么?
setTimeout(function() {
if (mycondition) {
//do work
}
}, 1000);
將等待1000毫秒並做聲明。 如果您的布爾條件是基於事件的事物,那么您可以聽取它。 是什么導致布爾值變為真? 聽起來超時是無關緊要的,所以我們只需要每100毫秒檢查一次:
setInterval(function() {
if (mycondition) {
//do work
}
}, 100);
這對你有幫助嗎?
所以完整的解決方案:
var mytimeout, myinterval;
mytimeout = setTimeout(function() {
//do work
clearInterval(myinterval);
}, 5000);
myinterval = setInterval(function() {
if (condition) {
clearTimeout(mytimeout);
//dowork
}
}, 100);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.