在前端开发中,异步代码的出错是无法避免的。为了提高应用程序的稳定性,开发者通常需要对可能出错的地方进行错误处理。RxJS 提供了许多操作符帮助我们处理异步错误。本文将深入介绍 RxJS 中的 retryWhen 操作符及其应用场景分析。
什么是 retryWhen 操作符
retryWhen 操作符是 RxJS 中的一个可重试错误操作符。当一个 Observable 出错时,retryWhen 操作符会重新订阅该 Observable。如果在指定的时间内还没有得到正确的响应,再次出错,则操作符将不再重试。
retryWhen 用法
retryWhen 操作符接收一个返回 Observable 的函数作为参数。如果 Observable 出错,就会调用该函数。该函数返回的 Observable 会决定是否要将 Observable 重试或停止重试。如果 Observable 出错,重新订阅 Observale,然后重试原始请求。
import { interval, of, throwError } from 'rxjs'; import { mergeMap, retryWhen, delay } from 'rxjs/operators'; const source = interval(1000); const example = source.pipe( mergeMap(val => { if (val > 5) { return throwError('Error!'); } return of(val); }), retryWhen(errors => errors.pipe( delay(1000) ) ) ); example.subscribe({ next: val => console.log(val), error: val => console.log(`${val}: Retried 3 times then quit!`) });
上面的代码,每当值大于 5 时,就会出现错误,并在出错后调用 retryWhen() 方法。在该方法中,我们使用延迟操作符来等待 1 秒钟,然后重试 3 次。如果重试次数已达 3 次,就会停止重试。
retryWhen 实际应用场景
1. 请求失败后的重试
在请求时可能会遇到一些网络故障等问题,这将导致请求失败。为了减少出错的概率和提高应用程序的稳定性,我们可以使用 retryWhen() 方法重试。
import { of, throwError, timer } from 'rxjs'; import { ajax } from 'rxjs/ajax'; import { mergeMap, retryWhen, map } from 'rxjs/operators'; const api = 'https://xxx.xxx.com/api/v1/users'; ajax.getJSON(api).pipe( retryWhen(errors => errors.pipe( mergeMap(error => error.status === 429 // 请求频次超过限制 ? timer(5000) : throwError({ error: error.message, status: error.status }) ) )) ).subscribe({ next: result => console.log(result), error: error => console.log(error) });
在这个例子中,当发生 429 错误(请求频次超过限制)时,我们需要等待 5 秒,然后尝试再次请求。我们可以使用 retryWhen() 方法(以及 mergeMap() 和 timer())来实现这个目标。
2. 实现超时机制
当我们发送一些请求时,可能会出现慢速响应的情况,这将导致访问变慢甚至无响应。为了避免等待时间过长的情况,我们可以使用 retryWhen() 方法和 timer() 操作符来实现超时机制。
import { of, throwError, timer } from 'rxjs'; import { ajax } from 'rxjs/ajax'; import { mergeMap, retryWhen, map, takeUntil, delay } from 'rxjs/operators'; const api = 'https://xxx.xxx.com/api/v1/users'; ajax.getJSON(api).pipe( map(result => result.data), mergeMap(data => timer(2000).pipe( map(() => data), takeUntil(of('timeout').pipe(delay(10000))) // 设置等待10秒 )), retryWhen(errors => errors.pipe( mergeMap(error => error === 'timeout' ? throwError('请求超时') : timer(2000).pipe(map(() => error)) ) )) ).subscribe({ next: result => console.log(result), error: error => console.log(error) });
在这个例子中,当网络请求超过 10 秒没有响应时,程序会停止重试。这里,我们通过 takeUntil() 方法,来停止整个 Observable,以避免不必要的超时请求。
3. 根据错误类型定制重试策略
我们有时可能需要对不同的错误类型采用不同的重试策略。我们可以在 retryWhen() 方法中针对不同的错误类型编写不同的重试策略,以便在遇到特定错误类型时,采用特定的重试策略。
const api = 'https://xxx.xxx.com/api/v1/users'; ajax.getJSON(api).pipe( map(result => result.data), mergeMap(data => timer(2000).pipe( map(() => data), takeUntil( of(false).pipe(delay(10000)) ) )), retryWhen(errors => errors.pipe( mergeMap((error, retryCount) => { if (retryCount >= 3) { return throwError({ type: 'fatal', message: 'Retried 3 times then quit' }); } else if (error.status === 429) { return timer(5000); } else { return timer(2000); } }) )) ).subscribe({ next: result => console.log(result), error: error => console.log(error) });
在这个例子中,当请求遇到严重错误时,我们给用户提供了一个很好的反馈,表示该请求已重试 3 次并已停止重试。同时,我们针对 status 为 429 的情况,进行了 5 秒无限制的重试,并延迟 2 秒进行其他错误的重试。
总结
在本文中,我们深入介绍了 RxJS 中的 retryWhen 操作符及应用场景分析。通过应用实例,我们从多个角度了解了 retryWhen 操作符的用法,并了解了其在实际开发中的重要作用和应用场景。仔细阅读本文,并实践出自己的应用,可以帮助前端开发者更好地处理异步错误和提高应用程序的健壮性。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65aa75deadd4f0e0ff40f935