Подтвердить что ты не робот

Какая разница между вилкой и нерестится в редукс-саге?

docs говорят, что fork - прикрепленная вилка, а spawn - отдельная вилка - как они отличаются?

4b9b3361

Ответ 1

Один из способов взглянуть на это - увидеть вашу сагу в виде графика. 'fork' создает дочерний элемент из вызывающего процесса. В то время как "spawn" создает нового потомка в корне графа.

Поэтому, когда вы "разветвляете" другой процесс, родительский процесс будет ждать, пока "разветвленный" процесс не будет завершен. Также каждое исключение будет передаваться от ребенка к родителю и может быть перехвачено родителем.

"Порожденный" процесс не блокирует родительский процесс, поэтому следующий оператор yield вызывается немедленно. Также родительский процесс не сможет перехватывать какие-либо исключения, которые происходят в "порожденном" процессе.

Я надеюсь, что это было полезно.

Ответ 2

В тех же документах говорится:

Когда родитель завершает выполнение своего собственного тела инструкций, он будет ожидать завершения всех разветвленных задач перед возвратом.

Допустим, у нас есть такая установка, где в середине потока выполнения мы вызываем fetchAll() которая может вызывать fork или spawn:

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, так как сам разветвление неблокирует, и внутренние разветвленные процессы будут leak из процессов внешнего разветвления, но будут храниться в ближайшем контексте блокировки. Это суть attachment to parent.

Поэтому родительский yield call(forkedProcess), имеющий блокирующую природу, будет ожидать throw resolution return или throw resolution дочерних процессов разветвления.

Однако это не относится к spawn(), так как spawn отделен от включающего родительского процесса, то есть присоединен к корневому процессу, поэтому локальный parent не должен ждать.

Надеюсь, это прояснит это немного.