在经过一段时间或满足条件后运行代码
Run code after some time has passed or a condition is met
编写代码的最佳和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);
以下代码使用两个全局变量condition
和seconds
。计时器每秒运行一次,如果condition
不是true
或seconds
不超过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);
相关文章:
- AJAX调用运行C代码的最佳实践
- 在经过一段时间或满足条件后运行代码
- 在Firefox restartless插件中,当一个新窗口打开时,我如何运行代码(监听窗口打开)
- 如果调试器关闭,Internet Explorer将出现运行代码问题
- JQuery 帖子未在 PHP 文件中运行代码
- 当ajax请求发生时运行代码的Chrome扩展
- 当我运行代码时,我得到以下结果 []对象对象] [对象对象],但应该给我一个有序数组
- 仅当客户端连接到Meteor服务器时才运行代码
- 在.each()循环中的ajax完成后,Jquery运行代码
- node.js和Cygein,我该如何运行代码
- 未访问全局变量,未运行代码
- Meteor - 在客户端上的异步回调的 for 循环后运行代码
- 运行代码以在Android应用程序中单击javascript按钮?尝试在页面上抓取回复按钮联系信息 craigslist
- 函数结束时如何运行代码
- JS 在不满足条件时在 if 语句中运行代码段
- 在 Ember 视图参数更改上运行代码
- 如何在 YUI 模块中运行代码
- 如何在未在 iframe 中定义的 iFrame 中运行代码
- 在后台运行代码,同时显示警报
- 加载页面时运行代码