/**
 * Helper for redux-saga, auto wrap saga with try-catch, prevent one throw stop all.
 * redux-saga工具集，为了业务健壮，自动将saga进行try-catch包装，避免一个出错导致其它saga也出错中止。
 *
 * @author cyrilluce@gmail.com
 */
import {
  takeEvery as _takeEvery,
  takeLatest as _takeLatest,
  throttle as _throttle,
  call,
  fork,
  cancel,
  take
} from "redux-saga/effects";

/**
 * Quick wrap a saga with `try catch`
 * 快速使用try catch包装saga
 * @param {Saga} saga
 */
export function tryCatch(saga) {
  const wrapped = function* wrappedTryCatch() {
    try {
      yield call(saga, ...arguments);
    } catch (e) {
      console.error("Error caught by redux-saga-catch: ", e);
    }
  };
  /** For debug trace. 用于调试时跟踪原始代码 */
  wrapped._original = saga;
  return wrapped;
}

/**
 * Like saga's takeEvery, but swallow exception and don't cancel the takeEveryHelper.
 * 类似于saga原生的takeEvery，但是出错也不会导致监听中止
 * @param {*} pattern
 * @param {Saga} worker
 * @param {*} args
 */
export function takeEvery(pattern, worker, ...args) {
  return _takeEvery(pattern, tryCatch(worker), ...args);
}

/**
 * Like saga's takeLatest, but swallow exception and don't cancel the takeLatestHelper.
 * 类似于saga原生的takeLatest，但是出错也不会导致监听中止
 * @param {*} pattern
 * @param {Saga} worker
 * @param {*} args
 */
export function takeLatest(pattern, worker, ...args) {
  return _takeLatest(pattern, tryCatch(worker), ...args);
}

/**
 * Like saga's throttle, but swallow exception and don't cancel the throttleHelper.
 * 类似于saga原生的throttle，但是出错也不会导致监听中止
 * @param {*} ms
 * @param {*} pattern
 * @param {Saga} worker
 * @param {*} args
 */
export function throttle(ms, pattern, worker, ...args) {
  return _throttle(ms, pattern, tryCatch(worker), ...args);
}

/**
 * run child sagas parallel, and child saga's exception don't cancel current saga.
 * 并行执行多个子saga，并且子saga出错不会影响父saga以及其它同级saga。
 *
 * usage/用法:
 * yield parallel([function*(){}, ...sagas])
 * @param {Saga[]} sagas
 */
export function parallel(sagas) {
  return call(function*(sagas) {
    for (let i = 0; i < sagas.length; i++) {
      yield fork(tryCatch(sagas[i]));
    }
  }, sagas);
}

/**
 * similar to takeLatest, buy fork saga first.
 * 与takeLatest相似，但会先fork执行一次saga。
 * takeLatest:  while( pattern ){ saga }
 * runAndTakeLatest:  do{ saga }while( pattern )
 * @param {*} pattern
 * @param {*} saga
 * @param {*} args
 */
export function runAndTakeLatest(pattern, saga, ...args) {
  saga = tryCatch(saga);
  return fork(function*() {
    let lastTask, action;
    while (true) {
      if (lastTask) {
        yield cancel(lastTask); // cancel is no-op if the task has already terminated
      }
      lastTask = yield fork(saga, ...args, action);
      action = yield take(pattern);
    }
  });
}

@@ -367,125 +367,458 @@
 %0A * 
-Quick wrap a saga with %60try catch%60%0D%0A * %E5%BF%AB%E9%80%9F%E4%BD%BF%E7%94%A8try catch%E5%8C%85%E8%A3%85saga%0D%0A * @param %7BSaga%7D saga%0D%0A */%0D%0Aexport function tryCatch(saga
+The default error handler which calls %60console.error%60%0D%0A * %E8%B0%83%E7%94%A8%60console.error%60%E7%9A%84%E9%BB%98%E8%AE%A4%E9%94%99%E8%AF%AF%E5%A4%84%E7%90%86%E7%A8%8B%E5%BA%8F%0D%0A * @param %7BError%7D error%0D%0A */%0D%0Aconst defaultErrorHandler = function(error) %7B%0D%0A  console.error(%22Error caught by redux-saga-catch: %22, error);%0D%0A%7D;%0D%0A%0D%0A/**%0D%0A * Quick wrap a saga with %60try catch%60%0D%0A * %E5%BF%AB%E9%80%9F%E4%BD%BF%E7%94%A8try catch%E5%8C%85%E8%A3%85saga%0D%0A * @param %7BSaga%7D saga%0D%0A * @param %7BFunction%7D %5BerrorHandler=defaultErrorHandler%5D%0D%0A */%0D%0Aexport function tryCatch(saga, errorHandler = defaultErrorHandler
 ) %7B%0D
@@ -946,60 +946,21 @@
     
-console.error(%22Error caught by redux-saga-catch: %22, 
+errorHandler(
 e);%0D
@@ -2285,41 +2285,134 @@
 %0D%0A *
-/%0D%0Aexport function parallel(sagas
+ @param %7BFunction%7D %5BerrorHandler=defaultErrorHandler%5D%0D%0A */%0D%0Aexport function parallel(sagas, errorHandler = defaultErrorHandler
 ) %7B%0D
@@ -2488,24 +2488,24 @@
 th; i++) %7B%0D%0A
-
       yield 
@@ -2526,16 +2526,30 @@
 sagas%5Bi%5D
+, errorHandler
 ));%0D%0A   

Allow a custom errorHandler in parallel + tryCatch (#2)