佐贺县的“全部屈服”并没有等待所有效果完成

时间:2018-10-30 19:30:32

标签: reactjs redux redux-saga

我有一个像这样的传奇人物(一些伪货)。

Saga1调用一个API。根据结果​​,我需要调用另外两个API。如果所有API都成功,则我调用onSuccess,否则调用onFailure。

该代码似乎可以正常运行,但效果不尽人意。我面对yield all时遇到的问题是,一旦调用第一个收益看跌期权,它就认为saga2和saga3已完成(请参阅saga2 / 3中的评论)。它没有等待提取结果完成。

我认为部分原因是由于我对“完全效果”的含义有误解。但是除此之外,我希望让所有人都等到一切完成。我希望saga2 / 3中的fetch引发的任何异常都被saga1中的catch捕获。

saga1(action) {

    const { onSuccess, onFailure } = action.payload;

    try {
        yield fetch...

        if(response.some_condition) yield all([
            put(saga2()),
            put(saga3())
        ])

        onSuccess();

    }
    catch(e) {
        onFailure();
    }
}

saga2(action) {

    yield put(someaction()) // This yields
    yield fetch...
}

saga3(action) {

    yield put(someaction()) // This yield
    yield fetch...
}

下面的这段代码与我下面关于渔获不起作用的注释有关

action1 () { // action2 is same
    try {
        yield fetch();
        yield put(FINISHED_1);
    }
    catch(e) {
        throw (e);
    }
}

saga1() {
    try {
        yield put(action1());
        yield put(action2());

        yield all([
            take(FINISHED_1),
            take(FINISHED_2),
        ])
        console.log("this doesn't print if exception in either action");
    }
    catch(e) {
        console.log("this doesn't print if exception in either action");
    }
    finally {
        console.log("this prints fine");
    }
}

1 个答案:

答案 0 :(得分:3)

1)要等待多个call效果运行完成:

yield all([
    call(saga2, arg1, arg2, ...),
    call(saga3, arg1, arg2, ...)
]);

2)要分派多个动作并等待其成功动作被分派:

yield put(action1());
yield put(action2());

yield all([
    take(ACTION_1_SUCCESS),
    take(ACTION_2_SUCCESS)
]);

编辑对评论的回应

如果您直接用all(上面的#1)致电sagas,则可以按常规捕获错误

try {
    yield all([
        call(saga2, arg1, arg2, ...),
        call(saga3, arg1, arg2, ...)
    ]);
} catch (e) {
    // ...
}

但是,如果其他Sagas监听到传奇put的动作,则该传奇不会收到这些异常。 Saga1不是这些sagas的父级或附属于此。它只是调度动作,其他地方的其他一些任务则监听和响应。

要让Saga1知道这些sagas中的错误,sagas不应抛出错误,而应使用错误有效负载调度操作:

function* saga2(action) {
    try {
        const result = yield call(...);
        yield put(action2Success(result));
    } catch (e) {
        yield put(action2Failure(e.message));
    }
}

通过saga2触发put(action2())的传奇可以处理成功和失败:

function* saga1(action) {
    yield put(action2());
    yield put(action3());

    const [success, failure] = yield race([
        // if this occurs first, the race will exit, and success will be truthy
        all([
            take(ACTION_2_SUCCESS),
            take(ACTION_3_SUCCESS)
        ]),

        // if either of these occurs first, the race will exit, and failure will be truthy
        take(ACTION_2_FAILURE),
        take(ACTION_3_FAILURE)
    ]);

    if (failure) {
        return;
    }

    // ...
}

Sagas应该处理异常并以错误状态更新商店,而不是抛出错误。使用saga并发构造时,sagas中的抛出错误会变得混乱。例如,您不能直接捕获fork ed任务引发的错误。此外,使用动作来发出传奇结果的信号会在您的商店中保留一个良好的事件日志,其他sagas / reducer可以对此做出响应。当您call进行其他Sagas时,原本应该触发该传奇的动作(例如takeEvery(THE_ACTION, ...))不会被分派。