我的移动应用程序连续将多个文件上传到服务器,通常来自连接强度可疑的偏远地区。出于这个原因,我想尝试发送文件。我还想继续并在发生故障时尝试下一个,并在导出结束时显示所有错误消息(即“上传10个文件,3个失败......”)
然而,我在使用promises计算递归重试模式时遇到了麻烦。这是我到目前为止所做的:
sendFile(params, retries = 3){
console.log("SENDING FILE: ", retries, "attempts remaining", params)
return new Promise((resolve, reject)=>{
if(retries > 0){
this._sendFile(params)
.then(()=>{
// Upload Success
console.log("Upload Success!")
resolve()
})
.catch((err)=>{
console.log("Upload Fail", err)
// Retry
this.sendFile(params, --retries)
})
}else{
console.log("Failed 3 times!!!")
//Record error
this.exportStatus.errors.push({
message:"A file failed to upload after 3 attempts.",
params: params
})
//Resolve and move on to next export
resolve()
}
})
}
_sendFile(params){
// Mobile - File Transfer
let options = {
fileKey: "file_transfer",
fileName: params.fileName,
httpMethod: "PUT",
chunkedMode: false,
headers: {
"x-user-email":this.settings.user.email,
"x-user-token":this.settings.user.authentication_token,
}
}
let fileTransfer = this.transfer.create()
let url = encodeURI(this.settings.api_endpoint + params.url)
return fileTransfer.upload(params.file, url, options, true)
}
当我在服务器上引发异常时,我会看到“失败3次!!!”错误消息,但调用的promise不会解析其余的导出以继续。我相信这是因为我创建了嵌套的promises(即每次重试都会创建一个新的promise)。如何在3次重试后解决原始承诺?
谢谢!
答案 0 :(得分:3)
您可以为Promise()
实现一个自动链接重试的包装器,允许您使用您需要的任何逻辑重构代码,而不必担心同时处理重试逻辑。您的用法可能如下所示:
sendFile(params, retries = 3) {
return Promise.retry(retries, (resolve, reject) => {
this._sendFile(params).then(resolve, reject)
})
}
以下是如何实施Promise.retry()
:
Object.defineProperty(Promise, 'retry', {
configurable: true,
writable: true,
value: function retry (retries, executor) {
console.log(`${retries} retries left!`)
if (typeof retries !== 'number') {
throw new TypeError('retries is not a number')
}
return new Promise(executor).catch(error => retries > 0
? Promise.retry(retries - 1, executor)
: Promise.reject(error)
)
}
})
Promise.retry(100, (resolve, reject) => {
// your sendFile core logic with proper
// calls to resolve and reject goes here
const rand = Math.random()
console.log(rand)
if (rand < 0.1) resolve(rand)
else reject(rand)
}).then(
value => console.log(`resolved: ${value}`),
error => console.log(`rejected: ${error}`)
)
&#13;
如果您对扩展本机对象感到不舒服(这是正确的方法,因为它是可配置的,不可枚举和可写的属性),您可以将其实现为静态函数:< / p>
function retry (retries, executor) {
console.log(`${retries} retries left!`)
if (typeof retries !== 'number') {
throw new TypeError('retries is not a number')
}
return new Promise(executor).catch(error => retries > 0
? Promise.retry(retries - 1, executor)
: Promise.reject(error)
)
}
答案 1 :(得分:1)
以下是最终工作的内容:
sendFile(params, retries = 3, promise = null){
console.log("SENDING FILE: ", retries, "attempts remaining", params)
if(retries > 0){
return this._sendFile(params)
.then(()=>{
// Upload Success
console.log("Upload Success!")
return Promise.resolve(true)
})
.catch((err)=>{
console.log("Upload Fail", err)
this.exportStatus.retries++
return this.sendFile(params, --retries) // <-- The important part
})
}else{
console.log("Failed 3 times!!!")
this.exportStatus.errors.push({
message:"A file failed to upload after 3 attempts.",
params: params
})
return Promise.resolve(false)
}
}
答案 2 :(得分:0)
帕特里克·罗伯茨(Patrick Roberts)发布的内容的后续活动, 如何在打字稿中实现它的示例:
type promiseExecutor<T> = (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void;
class RetryablePromise<T> extends Promise<T> {
static retry<T>(retries: number, executor: promiseExecutor<T>): Promise<T> {
return new RetryablePromise(executor).catch(error =>
retries > 0 ? RetryablePromise.retry(retries - 1, executor) : RetryablePromise.reject(error)
);
}
}
,用法如下:
RetryablePromise.retry(4, (resolve, reject) => console.log('run'));
答案 3 :(得分:0)
为了完整起见,这是一个简单的版本:
export async function promiseRetry<T>(fn: () => Promise<T>, retries = 5, err?: any): Promise<T> {
await new Promise(resolve => setTimeout(resolve, (5 - retries) * 1000));
return !retries ? Promise.reject(err) : fn().catch(error => promiseRetry(fn, (retries - 1), error));
}
内置重试逻辑,不需要的可以注释掉。
用法:
const myVal = await promiseRetry(() => myPromiseFn())