web-dev-qa-db-ja.com

redux-sagaのforkとspawnの違いは何ですか?

docs たとえばforkはattached forkで、spawnはdetached fork-どのように違いますか?

27
PaulB

それを見る一つの方法は、あなたの物語をグラフとして見ることです。 'fork'は、呼び出しプロセスから子を作成します。 「spawn」はグラフのルートに新しい子を作成します。

したがって、別のプロセスを「フォーク」すると、親プロセスは「フォーク」プロセスが終了するまで待機します。また、すべての例外は子から親にバブルアップし、親でキャッチできます。

ただし、「生成された」プロセスは親をブロックしないため、次の「yield」ステートメントがすぐに呼び出されます。また、親プロセスは、「生成された」プロセスで発生する例外をキャッチできません。

これがお役に立てば幸いです。

26
Alex

同じドキュメントで次のように書かれています:

親が自身の命令本体の実行を終了すると、分岐するすべてのタスクが終了するのを待ってから戻ります。

実行フローの途中でforkまたはspawnを呼び出すfetchAll()を呼び出すこのセットアップがあるとします。

_const { delay, runSaga } = require("redux-saga");
const fetch = require("node-fetch");
const { fork, spawn, call, put} = require("redux-saga/effects");


function* fetchResource(resource) {
    console.log(`Fetch ${resource} start`);
    const response = yield call(fetch, "https://jsonplaceholder.typicode.com" + resource);
    const text = yield call(response.text.bind(response));
    console.log(`Fetch ${resource} end`);
}

function* fetchAll() {
    console.log("Fork or Spawn start");
    // this is pseudo code, I mean here that you can use either
    // fork or spawn, check results below
    const task1 = yield fork||spawn(fetchResource, "/posts/1"); 
    const task2 = yield fork||spawn(fetchResource, "/posts/2");
    console.log("Fork or Spawn end");
}

function* main() {
    console.log("Main start");
    yield call(fetchAll);
    console.log("Main end");
}

runSaga({}, main);

// RESULTS WITH FORK():   |  RESULTS WITH SPAWN():
//                        |
// Main start             |  Main start
// Fork start             |  Spawn start
// Fetch /posts/1 start   |  Fetch /posts/1 start
// Fetch /posts/2 start   |  Fetch /posts/2 start
// Fork end               |  Spawn end
// Fetch /posts/2 end     |  Main end <-- 
// Fetch /posts/1 end     |  Fetch /posts/2 end
// Main end <--           |  Fetch /posts/1 end
_

わかるのは、callコンテキスト内では、フォークは_non-blocking_ですが、call自体がブロッキング効果であるため、callはすべての子プロセスが終了するまで終了しません。

別のfork内でforkを呼び出した場合、fork自体は非ブロッキングであり、内側のフォークされたプロセスは外側のforkプロセスからleakになりますが、最も近いブロッキングコンテキスト内に保持されるため、同じようには見えません。これが_attachment to parent_の本質です。

そのため、親yield call(forkedProcess)は、ブロッキングの性質を持ち、子フォークプロセスのreturnまたは_throw resolution_を待機します。

ただし、spawn()の場合はそうではありません。スポーンは親プロセスから切り離されているため、つまりルートプロセスにアタッチされているため、ローカルのparentは待機する必要がありません。

これが少し明確になることを願っています。

20
Karen Grigoryan