在经过一段时间或满足条件后运行代码

Run code after some time has passed or a condition is met

本文关键字:运行 代码 条件 满足 经过 一段时间      更新时间:2023-09-26

编写代码的最佳和DRYest方法是什么?当经过一段时间(例如5秒)或满足某个条件(例如bool = true)时,可以执行该代码-,以先到者为准。五秒钟从脚本第一次运行时开始计数,布尔值是一个全局值,由另一个函数更改。我不认为你可以把暂停和bool检查结合在一个声明中,但另一个好的方法也是好的。

伪代码:

if (bool = true OR timePassed = 5000):
    runCode()

没有一个答案真正提供了问题的完整答案,即未实现(以先到者为准),或者最终代码运行了两次。

你需要一个计时器和一个条件(正如其他答案所建议的,但未能结合为一个整体)。

var done = false;
var thisTimeout = setTimeout(function() {
    myFunction();
}, 1000);
if ((someCondition) && !done) {
    myFunction();
}
function myFunction() {
    clearTimeout(thisTimeout);
    done = true;
    // Do stuff
}

如果函数在达到时间限制之前被调用,则可以设置超时并取消它。

var timeout = setTimeout(function() {
    runCode();
}, 5000);
function runCode() {
    clearTimeout(timeout);
    ...
}

编辑:现在我想起来了,在这种情况下设置超时的更好方法是

var timeout = setTimeout(runCode, 5000);

以下代码使用两个全局变量conditionseconds。计时器每秒运行一次,如果condition不是trueseconds不超过4,则将秒数增加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);

将等待1000ms并执行语句。如果你的布尔条件是基于事件的,那么你可以监听它。是什么导致布尔条件变成true?听起来超时是无关紧要的,所以我们只需要每隔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);