昨天领导提了一个问题,需要创建一个retry函数,目的是为了执行某一个函数,当函数执行成功则返回正确的结果,如果执行失败则需要在1000ms内执行当前函数4次直到返回正确结果,如果1000ms内还没有返回结果,则需要返回错误提示信息。
第一版
拿到这个问题之后,一顿操作猛如虎,其实没有什么用。
var executeFunction = function() {
var timespan = 250;
var maxCount = 4;
var executeCount = 0;
var success = function() {
console.log('success');
}
var fail = function() {
console.log('fail');
}
return function(callback) {
setTimeout(function() {
if (callback()) {
return success();
} else if (++executeCount < maxCount) {
arguments.callee();
} else {
return fail();
}
}, timespan);
}
}
var testFunction = function() {
var date = new Date();
console.log("execute testFunction: Date " + date.toString() + ". ms: " + date.getMilliseconds() );
return false;
}
executeFunction()(testFunction);
执行结果如下:
个人说明: 因为给的这个需求自己一开始没有搞清楚,然后leader要求5分钟再黑板上写出来。上面的这个版本也没有写完,上面的代码是我按照一开始的想法后续加上的。可以看到当前的执行时间间隔不是250ms。
执行这个结果的原因:
因为arguments.callee()指向的是当前执行的函数,当前执行的函数是setTimeout的第一个参数匿名函数,不是当前返回的函数,所以结果是错误的,因为后续的执行根本不走setTimeout。第二版
找到原因之后,我将返回的函数加上了一个名称当成具名函数,然后再去调用这个函数就可以了。var executeFunction = function() {
var timespan = 250;
var maxCount = 4;
var executeCount = 0;
var success = function() {
console.log('success');
}
var fail = function() {
console.log('fail');
}
return function returnFunction(callback) {
setTimeout(function() {
if (callback()) {
return success();
} else if (++executeCount < maxCount) {
returnFunction(callback);
} else {
return fail();
}
}, timespan);
}
}
var testFunction = function() {
var date = new Date();
console.log("execute testFunction: Date " + date.toString() + ". ms: " + date.getMilliseconds() );
return false;
}
executeFunction()(testFunction);
leader的本意
其实在我们将代码书写在黑板上写过之后,当然没有完成。leader说当我看到你们写代码的时候,你们写代码是在做1+1=2的过程。这个1+1=2的含义是什么呢?(在领导的抽象说明之后的个人臆测)
写代码的时候上来就是一些不是关键的东西写出来了,例如1000ms,执行4次的条件在代码了写出来了。如上图:我们其实将这个问题的分析走了一个逆向的思维,是先考虑了比较detail的问题,然后执行1+1最后生成最后的代码。
leader的本意应该如下(当然还是我的臆测)
leader的想法是让我们做f(x, y),让我们从上往下考虑。
/*retry*/
var retry = function(functionName, retryCondition, retryConfig) {
if (typeof functionName != 'function') {
return "functionName should be function!";
}
if (typeof retryCondition != 'function') {
return "retryCondition should be function!";
}
if (typeof retryConfig != 'object') {
return "retryConfig should be object!";
}
retryConfig.retryTimeRange = retryConfig.retryTimeRange || 0;
retryConfig.retryCount = retryConfig.retryCount || 1;
var returnValue = functionName();
var retryIndex = 0;
if (!retryCondition(returnValue)) {
return returnValue;
} else {
var retryTimeSpan = retryConfig.retryTimeRange / retryConfig.retryCount;
(function retry() {
setTimeout(function() {
var returnValue = functionName();
if (!retryCondition(returnValue)) { /*return true will try*/
return returnValue;
} else if (++retryIndex < retryConfig.retryCount) {
retry();
} else {
console.info("fail returnvalue: " + returnValue);
return returnValue;
}
}, retryTimeSpan);
})(functionName);
}
}
/*test*/
var functionName1 = function() {
var returnValue = Math.random() * 100;
/*log innfo*/
var date = new Date();
console.info("execute testFunction: Date " + date.toString() + ". ms: " + date.getMilliseconds() );
console.info("returnvalue: " + returnValue);
return returnValue;
}
var retryCondition1 = function(returnValue) {
if (returnValue > 80) {
return false;
}
return true;
}
var retryConfig1 = {
retryTimeRange: 1000,
retryCount: 5
}
retry(functionName1, retryCondition1, retryConfig1);
我们看一下返回的结果(这里的测试是使用随机数返回值,如果随机数*100 > 80则返回值,如果retry时间到了还没有正确答案,则返回值并标明是错误的结果的),下面的三次返回前两次存在正确返回值,最后一次五次retry还是没有正确的返回值。
延伸:如何处理Ajax,我的想法是借助Promise,这样我们可以控制函数执行什么时候返回结果。我认为只要将Promise包装函数就可以了。
写到这里,上文都是自己的一些感悟吧,无论对错,希望大家指出来不对和改进的地方。