简体   繁体   English

RxJS Observable:重试失败的 Promise

[英]RxJS Observable: retry a Promise that fail

I have been trying to create a functionality that resolve 3 promises, I any of this promises fails, I want to retry it.我一直在尝试创建一个解决 3 个承诺的功能,我这个承诺中的任何一个都失败了,我想重试。 My idea is: if the second promise fail, the 1st and 3rd promise should be resolved anyway the suscriptor could be notified.我的想法是:如果第二个承诺失败,无论如何都应该解决第一个和第三个承诺,可以通知订阅者。

that is my code:那是我的代码:

const endpointsRequest = [
    axios.get("https://restcountries.eu/rest/v2/name/aruba?fullText=true"),
    axios.get("http://localhost:8080"),
    axios.get("https://restcountries.eu/rest/v2/name/argentina?fullText=true")
];

return Observable
    .forkJoin(endpointsRequest)
    .switchMap( promise => Observable.defer(() => promise) )
    .retry(3)
    .subscribe(
        (x) => {
            console.log("=======================================");
            console.log("Result", x.data.length? x.data[0] : x.data);
            console.log("=======================================");
        },
        (err) => {
            console.log("=======================================");
            console.log(`Error: ${err}`)
            console.log("=======================================");
        },
        () => {
            console.log("=======================================");
            console.log("Completed");
            console.log("=======================================");
        }
    );

It is possible achieve this?有可能实现这一目标吗?

example of response if using this promises array:使用此 promises 数组时的响应示例:

Promises Array承诺数组

const endpointsRequest = [
        axios.get("https://restcountries.eu/rest/v2/name/aruba?fullText=true"),
        axios.get("https://restcountries.eu/rest/v2/name/argentina?fullText=true")
    ];

Response回应

=======================================
Result { name: 'Aruba',
  topLevelDomain: [ '.aw' ],
  alpha2Code: 'AW',
  alpha3Code: 'ABW',
  callingCodes: [ '297' ],
  capital: 'Oranjestad',
  altSpellings: [ 'AW' ],
  region: 'Americas',
  subregion: 'Caribbean',
  population: 107394,
  latlng: [ 12.5, -69.96666666 ],
  demonym: 'Aruban',
  area: 180,
  gini: null,
  timezones: [ 'UTC-04:00' ],
  borders: [],
  nativeName: 'Aruba',
  numericCode: '533',
  currencies: [ { code: 'AWG', name: 'Aruban florin', symbol: 'ƒ' } ],
  languages: 
   [ { iso639_1: 'nl',
       iso639_2: 'nld',
       name: 'Dutch',
       nativeName: 'Nederlands' },
     { iso639_1: 'pa',
       iso639_2: 'pan',
       name: '(Eastern) Punjabi',
       nativeName: 'ਪੰਜਾਬੀ' } ],
  translations: 
   { de: 'Aruba',
     es: 'Aruba',
     fr: 'Aruba',
     ja: 'アルバ',
     it: 'Aruba',
     br: 'Aruba',
     pt: 'Aruba',
     nl: 'Aruba',
     hr: 'Aruba',
     fa: 'آروبا' },
  flag: 'https://restcountries.eu/data/abw.svg',
  regionalBlocs: [],
  cioc: 'ARU' }
=======================================
=======================================
Result { name: 'Argentina',
  topLevelDomain: [ '.ar' ],
  alpha2Code: 'AR',
  alpha3Code: 'ARG',
  callingCodes: [ '54' ],
  capital: 'Buenos Aires',
  altSpellings: [ 'AR', 'Argentine Republic', 'República Argentina' ],
  region: 'Americas',
  subregion: 'South America',
  population: 43590400,
  latlng: [ -34, -64 ],
  demonym: 'Argentinean',
  area: 2780400,
  gini: 44.5,
  timezones: [ 'UTC-03:00' ],
  borders: [ 'BOL', 'BRA', 'CHL', 'PRY', 'URY' ],
  nativeName: 'Argentina',
  numericCode: '032',
  currencies: [ { code: 'ARS', name: 'Argentine peso', symbol: '$' } ],
  languages: 
   [ { iso639_1: 'es',
       iso639_2: 'spa',
       name: 'Spanish',
       nativeName: 'Español' },
     { iso639_1: 'gn',
       iso639_2: 'grn',
       name: 'Guaraní',
       nativeName: 'Avañe\'ẽ' } ],
  translations: 
   { de: 'Argentinien',
     es: 'Argentina',
     fr: 'Argentine',
     ja: 'アルゼンチン',
     it: 'Argentina',
     br: 'Argentina',
     pt: 'Argentina',
     nl: 'Argentinië',
     hr: 'Argentina',
     fa: 'آرژانتین' },
  flag: 'https://restcountries.eu/data/arg.svg',
  regionalBlocs: 
   [ { acronym: 'USAN',
       name: 'Union of South American Nations',
       otherAcronyms: [Array],
       otherNames: [Array] } ],
  cioc: 'ARG' }
=======================================
=======================================
Completed
=======================================

Promises Array承诺数组

const endpointsRequest = [
        axios.get("https://restcountries.eu/rest/v2/name/aruba?fullText=true"),
        axios.get("http://localhost:8080"),
        axios.get("https://restcountries.eu/rest/v2/name/argentina?fullText=true")
    ];

response回应

=======================================
Error: Error: connect ECONNREFUSED 127.0.0.1:8080
=======================================
  1. How to retry promise?如何重试承诺?

Promise itself can't be retried once settled down.一旦稳定下来,Promise 本身就无法重试。 So Observable starts from direct Promise also can't be retried via retry operator.所以 Observable 从直接 Promise 开始也不能通过retry操作符重retry One way is using defer operator, creating new promise each time it subscribes into.一种方法是使用defer运算符,每次订阅时都会创建新的承诺。

Rx.Observable.defer(() => return somePromise).retry(.....)
  1. Why if a promise fail the another are not resolved?为什么如果一个承诺失败另一个没有得到解决?

Nature of forkJoin operator expects all observable should complete with value emission. forkJoin运算符的性质期望所有observable 都应该完成值发射。 Either one fails or completes without value, it short-curcuits execution.要么失败要么完成没有价值,它会缩短执行时间。 To make forkJoin emits completed values, inner observalbe (param of forkJoin) must handle accordingly to not error / and complete with values.为了使 forkJoin 发出完整的值,内部观察(forkJoin 的参数)必须相应地处理以不出错 / 并用值完成。

For anyone reading this who's using RxJS 6+: the following code works for us.对于使用 RxJS 6+ 阅读本文的任何人:以下代码适用于我们。 MyClass.connect() returns a Promise in this case. MyClass.connect()在这种情况下返回一个 Promise。

defer(() => from(MyClass.connect()))
  .pipe(retry(3))
  .subscribe(...)

Also for rxjs 6+ if you would like to retry on a condition如果您想在某个条件下重试,也适用于 rxjs 6+

let loginStatus = defer(()=>{return from(new Promise(FB.getLoginStatus))}).pipe(
map((res:any)=>{
    if(res.status !== "connected"){
        throw res
    }
    return res
}),
retryWhen((error)=>{

    return error.pipe(
        delay(3000)
    )
})).subscribe({
next:(result:any)=>{
    console.log(result)
},
error:(err:any)=>{
    console.log(err)
}})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM