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