佐贺县的“全部屈服”不是在等待所有效果完成

ahs*_*aus 4 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...
}
Run Code Online (Sandbox Code Playgroud)

下面的这段代码与我下面关于捕获不起作用的评论有关

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

bsa*_*aka 5

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

yield all([
    call(saga2, arg1, arg2, ...),
    call(saga3, arg1, arg2, ...)
]);
Run Code Online (Sandbox Code Playgroud)

2)调度多个动作并等待其成功动作被调度:

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

yield all([
    take(ACTION_1_SUCCESS),
    take(ACTION_2_SUCCESS)
]);
Run Code Online (Sandbox Code Playgroud)

编辑回应评论

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

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

但是,如果某个传奇事件被put其他传奇接受,则该传奇不会收到这些异常。Saga1不是这些英雄的父母。它只是调度动作,而其他地方的其他一些任务则监听和响应。

为了Saga1了解这些sagas中的错误,sagas不应抛出错误,而应调度一个带有错误有效负载的操作:

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

触发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;
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

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