javascript - 原生 JS Promise 重试包装器
问题描述
问题概述:
我在 FireFox 中有一个GreaseMonkey / TamperMonkey脚本,它向 URL 发送多个GM_xmlhttpRequest
(本质上类似于 xml http 请求,但是这个包装器允许轻松进行跨域请求)以检索简单的 JSON 数据。检索到的一些 JSON 数据非常简单,就像这样,
{id:123459876, code:"frog"}
[{value:"water", contents:0}]
这使我概述了到目前为止我为我的编程任务编写的代码,并最终形成了我最终要问的问题。
问题大纲: 由于我本质上正在做的工作流程如下;(基于这个SO问题/答案)
- 在对象内部发送
'GET'
请求GM_xmlhttpRequest
Promise
function makeRequest(reqMethod, navURL) {
return new Promise(function (resolve, reject) {
GM_xmlhttpRequest({
method: reqMethod,
url: navURL,
onload: function () {
if (this.status >= 200 && this.status < 300) {
resolve(this.response);
} else {
reject({
status: this.status,
statusText: this.statusText
});
}
},
onprogress: function(event) {
console.log(`Loaded ${event.loaded} of ${event.total}`);
},
onerror: function(data) {
reject({
status: this.status,
statusText: this.statusText
});
}
});
});
}
- 在
GM_xmlhttpRequest
- 中返回成功状态后,promise 将 JSON 作为解析响应返回。
function makeRequestWrapper(requestMethod, navToURL, successFunction) {
makeRequest(requestMethod, navToURL)
.then(
function (datums) {
successFunction(datums);
}
)
.catch(
function (err) {
console.error('there was an error!', err.statusText);
}
);
}
- 拥有初始承诺,在成功解决后,运行后处理函数以使用检索到的 JSON 数据更新当前窗口页面
// one of the 3 example handler methods for dealing with the success + JSON
function successHandler1(jsonDataResponse) {
let response = JSON.parse(jsonDataResponse);
let id = response[0].id;
let updateLink = document.getElementById("unique_link_id").parentNode.parentNode;
updateLink .innerHTML += ` ID: ${id} `;
}
到目前为止,我的代码按预期工作,Promise on success 返回 JSON 数据,我用检索到的数据更新当前窗口页面。
但是,我的问题是,提取此 JSON 数据的脚本的某些用户会遇到 Promise 失败(有些人比其他人更频繁) - 因此我正在尝试的下一步分类是重试 Promise 一定次数,并且,延迟。这样,我认为重试失败的 Promise,假设 3 次,延迟 3 秒,应该有足够的尝试和时间来提高 Promise 的成功率。
我的想法
由于我是 JS 的相对新手(仍在学习它并希望成为我可以在生活中使用的语言),我读过诸如Promises 和 Observables 之类的东西?并重新考虑我是否在解决这个问题的正确道路上。我认为我需要一个针对我的用例的深入示例,并通过详尽的分步说明来了解更多关于 Promises 以及这个用例场景的信息。
到目前为止,我已经尝试将我的工作代码与这些关于重试承诺的 SO 答案集成,例如:
- 承诺重试设计模式
- 通用承诺重试逻辑
- 重试 Javascript.Promise.reject 有限次数或直到成功
- Promise 中的递归重试
- 如何重试 xhr 请求,该请求在状态 0 上递归返回至少 n 次承诺
- Promises:重复操作直到成功?
- 在javascript中重试promise的通用解决方案
以及阅读博客文章,例如;
- 使用 Promise 在 Node.js 中重试模式
- JavaScript:Promise 以及为什么 Async/Await 会胜出
- 重试 Javascript 的 Sync/Async(Promises) 函数
我也看过无数的文档,比如;
- https://developer.mozilla.org/en-US/docs/Web/API/
- https://wiki.greasespot.net/
- https://javascript.info/
- https://devdocs.io/javascript/
最后,一些随机的(结构不太好的)链接;
问题
如何将现有代码转换为上述示例,或者创建一个类似 API 的新方法来处理现有代码(解决我现有的问题)?
解决方案
这是您的函数的包装器makeRequest()
,可让您传递最大重试次数和重试之间的延迟。它返回一个承诺,如果成功则解决,如果在 maxRetries 之后仍然有错误,则拒绝。
function makeRequestRetry(requestMethod, navToURL, maxRetry = 3, retryDelay = 3000) {
let retryCnt = 0;
function delay(t) {
return new Promise(resolve => {
setTimeout(resolve, t);
});
}
function run() {
return makeRequest(requestMethod, navToURL).catch(function (err) {
++retryCnt;
if (retryCnt > maxRetry) {
console.error('Max retries exceeded. There was an error!', err.statusText);
throw err;
}
console.error('Retry #' + retryCnt + ' after error', err.statusText);
// call ourselves again after a short delay to do the retry
// add to the promise chain so still linked to the originally returned promise
return delay(retryDelay).then(run);
});
}
return run();
}
而且,有人会这样称呼它:
makeRquestRetry('GET', someURL, 5, 5000).then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
或者,使用重试参数的默认值:
makeRquestRetry('GET', someURL).then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
推荐阅读
- c++ - 模板函数产生未定义的引用错误
- sql - 对关系代数的 SQL 查询
- angular - Angular:根据单选按钮选择指定路线
- python - 在forms.py和views.py中创建chiled类字段时如何更改父类中的字段?
- flutter - 是否可以在 Flutter 中使用路由器实时查看连接的设备?
- c++ - 数组c ++中的大括号初始化
- php - PHP - document.xml 到 document.pdf
- r - R 中带有“aqp”的彩色体积分数的土壤剖面
- javascript - javascript中的数字OCR(光学识别)
- .htaccess - 带有和不带斜杠的重定向到两个不同的 URL