簡體   English   中英

經過一段時間或滿足條件后運行代碼

[英]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
}

以下代碼使用兩個全局變量conditionseconds 計時器每秒運行一次,如果condition不為trueseconds不超過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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM