What's the difference between fork and spawn i

2019-03-17 10:49发布

The docs say fork is an attached fork and spawn is a detached fork - how do they differ?

标签: redux-saga
2条回答
孤傲高冷的网名
2楼-- · 2019-03-17 11:28

In the same docs it says:

When the parent terminates the execution of its own body of instructions, it will wait for all forked tasks to terminate before returning.

Let's say we have this setup where in the middle of execution flow we call fetchAll() that might call either fork or 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

What we see is, within call context the fork is non-blocking, but call is not going to finish until all its children processes are finalised, since call itself is a blocking effect.

You wouldn't see the same if you call a fork within another fork, since fork itself is non-blocking, and inner forked processes would leak out of outer fork processes, but will be kept inside the nearest blocking context. This is the essence of attachment to parent.

So parent yield call(forkedProcess) being of a blocking nature will await for return or throw resolution of child fork processes.

This is not the case with spawn(), however, since spawn is detached from enclosing parent process, i.e. attached to the root process, thus local parent doesn't have to wait.

Hope this clarifies it a bit.

查看更多
ゆ 、 Hurt°
3楼-- · 2019-03-17 11:37

One way to look at it is to see your saga's as a Graph. 'fork' creates a child from the calling process. While 'spawn' creates a new child at the root of the graph.

So when you 'fork' another process, the parent process will wait until the 'forked' process is finished. Also every exception will bubble up from the child to the parent and can be caught in the parent.

A 'spawned' process though will not block the parent, so the next 'yield' statement is called immediately. Also the parent process will not be able to catch any exceptions that happen in the 'spawned' process.

I hope this was helpful.

查看更多
登录 后发表回答