Error handling with RxJS

Summary

  • Imperative error handling has many drawbacks that make it incompatible with FP.

  • Value containers, likeTry, provide a fluent, expressive mechanism for transforming values immutably.

  • The Try wrapper is a functional data type used to consolidate and abstract exception handling so that you can sequentially map functions to values.

  • RxJS implements many useful and powerful operators that allow you to catch and retry failed operations in a way that doesn’t break the flow of the stream and the declarative nature of an RxJS stream declaration.

  • RxJS provides operators such as catch(),retry(),retryWhen(), andfinally() that you can combine to create sophisticated error-handling schemes.

1.下面这种错误处理方式,有很多缺点,这和函数式编程不兼容

ajax('/rest/api/data', data => {
    for (let item of data) {
      ajax(`/rest/api/data/${item.id}/info`, dataInfo => {
          ajax(`/rest/api/data/images/${dataInfo.img}`, showImage, error => {  //#A
            console.log(`Error image: ${error.message}`);
          });
        },
        error => { //#B
          console.log(`Error each data item: ${error.message}`);
        });
    }
  },
  error => {  //#C
    console.log(`Error fetching data: ${error.message}`);
  });

2.容器,比如Try,提供了一个流畅的机制,来改变值的不变???

3.Try是函数式的数据类型,用来合并抽象异常处理,以便将函数映射到值


try {
let record = findRecordById('123');
... potentially many lines of code in between
}
catch (e) {
console.log('ERROR: Record not found!');
// Handle error here
}

4.RxJS有很多有用的operators,来catch和retry

const computeHalf = x => Math.floor(x / 2);

Rx.Observable.of(2,4,5,8,10)
   .map(num => {
      if(num % 2 !== 0) {
        throw new Error(`Unexpected odd number: ${num}`); //#A
      }
      return num;
   })
   .map(computeHalf)
   .subscribe(
       function next(val) {
          console.log(val);
       },
       function error(err) {
          console.log(`Caught: ${err}`); //#B
       },
       function complete() {
          console.log('All done!');
       }
    );
//catch
Rx.Observable.of(2,4,5,8,10)
   .map(num => {
      if(num % 2 !== 0) {
        throw new Error(`Unexpected odd number: ${num}`);
      }
      return num;
   })
   .catch(err => Rx.Observable.of(6)) //#A
   .map(n => n / 2)
   .subscribe(
       function next(val) {
          console.log(val);
       },
       function error(err) {
          console.log(`Received error: ${err}`); //#B
       },
       function complete() {
          console.log('All done!');
       }
    );
//Result:
1
2
3
All done!
//retryWhen
const maxRetries = 3;
Rx.Observable.of(2, 4, 5, 8, 10)
  .map(num => {
    if (num % 2 !== 0) {
      throw new Error(`Unexpected odd number: ${num}`);
    }
    return num;
  })
  .retryWhen(errors$ =>
    Rx.Observable.range(0, maxRetries) //#A
      .zip(errors$, val => val)  //#B
      .mergeMap(i =>    //#C
        Rx.Observable.timer(i * 1000)
          .do(() => console.log(`Retrying after ${i} second(s)...`)))
  )
  .subscribe(console.log);
  //RESULT:
2
4
Retrying after 0 second(s)...
2
4
Retrying after 1 second(s)...
2
4
Retrying after 2 second(s)...
2
4

5.catch(),retry(),retryWhen(),andfinally(),可以用来合并创造复杂的错误处理

const maxRetries = 3;

Rx.Observable.of(2,4,5,8,10)
   .map(num => {
      if(num % 2 !== 0) {
        throw new Error(`Unexpected odd number: ${num}`);
      }
      return num;
   })
   .retryWhen(errors$ =>
       Rx.Observable.range(0, maxRetries + 1)
         .zip(errors$, (i, err) => ({'i': i, 'err': err})) //#A
         .mergeMap( ({i, err}) => {     //#B
             if(i === maxRetries) {
               return Rx.Observable.throw(err);  //#C
             }
             return Rx.Observable.timer(i * 1000)
               .do(() =>
                    console.log(`Retrying after ${i} second(s)...`));
        })
    )
   .subscribe(
    console.log,
    error => console.log(error.message)
   );

   //Result:
2
4
Retrying after 0 second(s)...
2
4
Retrying after 1 second(s)...
2
4
Retrying after 2 second(s)...
2
4
Unexpected odd number: 5

results matching ""

    No results matching ""