javascript - How would you automatically retry a failed ajax call 3 times (synchronously)?
问题描述
I'm trying to rerun a failed AJAX call 3 times. After the third attempt, I'd like to call a failed method. I don't want the AJAX calls to over run each other though.
What's the safest/best way to achieve this with what I'm working with?
I'm using a globalAjaxRequest method like so:
globalAjaxRequest(request, successCallback, errorCallback) {
let ajaxRequest = null;
if (request.url) {
const ajaxOptions = {
type: request.method ? request.method.toUpperCase() : 'POST',
url: request.url,
data: request.data || undefined,
beforeSend: request.beforeSend,
success: (data) => {
successCallback(data);
},
error: (data) => {
if (errorCallback) {
errorCallback(data);
}
}
};
ajaxOptions.dataType = request.dataType || 'json';
ajaxOptions.contentType = request.contentType || 'application/json; charset=utf-8';
if (request.contentType) {
ajaxOptions.data = $.parseJSON(JSON.stringify(ajaxOptions.data));
} else {
ajaxOptions.data = JSON.stringify(ajaxOptions.data);
}
ajaxRequest = $.ajax(ajaxOptions);
}
return ajaxRequest;
}
}
Here's my attempt:
callAPI() {
const callData = {
url: '/callApi',
data: {
id: 'something'
}
};
global.Utils.globalAjaxRequest(callData, (success) => {
console.log('success');
successMethod();
}, (fail) => {
for (let i = 1;; i++) {
i <= 3 && setTimeout(() => {
callAPI();
}, 1000);
if (i > 3) {
failedMethod();
break;
}
}
});
}
callAPI();
解决方案
您不能重试异步操作,例如$.ajax()
同步,所以我假设您只是想在失败时自动按顺序重试。
这是一个通用的重试函数$.ajax()
:
// general purpose promise delay, useful when you want to delay a promise chain
function pDelay(t, v) {
return new Promise(function(resolve) {
setTimeout(resolve, t, v);
});
}
// three arguments:
// options: value for $.ajax(options) - does not support other forms of calling $.ajax()
// delay: amount of time in ms to delay before each retry (can be 0 if you want)
// retries: number of times to retry, defaults to 3 if you don't pass it
$.ajaxRetry = function(options, delay, retries) {
// default value for retries is 3 if the argument is not passed
let retriesRemaining = retriesRemaining !== undefined ? retriesRemaining: 3;
let opts = Object.assign({}, options);
function run() {
return $.ajax(opts).catch(function(err) {
--retriesRemaining;
// don't fire this more than once
delete opts.beforeSend;
if (retriesRemaining > 0) {
// try again after short delay
return pDelay(delay).then(run);
} else {
// hit max retries, propagate error back to caller
throw e;
}
});
}
return run();
}
仅供参考,此代码假定您的情况下的“失败”意味着$.ajax()
拒绝的承诺。如果“失败”意味着其他东西(例如查看您得到的某些结果),那么您将不得不将该附加测试插入重试循环或公开一个回调,以便可以在外部提供该附加测试。
要将其集成到您的包装器中,您可以这样做:
globalAjaxRequest(request, successCallback, errorCallback) {
let ajaxRequest = null;
if (request.url) {
const ajaxOptions = {
type: request.method ? request.method.toUpperCase() : 'POST',
url: request.url,
data: request.data || undefined,
beforeSend: request.beforeSend,
};
ajaxOptions.dataType = request.dataType || 'json';
ajaxOptions.contentType = request.contentType || 'application/json; charset=utf-8';
if (request.contentType) {
ajaxOptions.data = $.parseJSON(JSON.stringify(ajaxOptions.data));
} else {
ajaxOptions.data = JSON.stringify(ajaxOptions.data);
}
errorCallback = errorCallback || function(err) { throw err; };
ajaxRequest = $.ajaxRetry(ajaxOptions, 0, 3).then(successCallback, errorCallback);
}
return ajaxRequest;
}
}
仅供参考,采用 Promise 接口并将其转换回普通回调有点奇怪。看来您应该摆脱successCallback
并errorCallback
让调用者使用返回的承诺。
推荐阅读
- reactjs - 表单数据的axios post请求什么都不发送
- python - jupyter notebook 中 astroplan 命令的 JSONDecodeError
- javascript - 防止我的烧瓶应用程序重新加载,以免重新加载我的 javascript 并显示计时器
- java - 无法播放此视频。MediaPlayer:无法打开 /storage/emulated/0/...mp4
- python-3.x - 调用 pipenv shell 时出错
- java - 如何使用 Stream#reduce 提高字符串处理的性能?
- reactjs - 将普通变量转换为状态变量,同时处理异步问题
- flutter - 使用类型转换方法 (.toObjectBox) 在 ObjectBox 中存储嵌套数据结构
- c# - WPF Datagrid Binding:访问视图模型中绑定集合的当前评估项
- r - 在 r 中的一组中分配小于 5 的数据