web-dev-qa-db-fra.com

Quelle est la différence entre fork et spawn dans redux-saga?

docs disons que fork est une fourche attachée et que spawn est une fourche détachée - en quoi diffèrent-ils?

27
PaulB

Une façon de voir les choses est de voir votre saga sous forme de graphique. 'fork' crée un enfant à partir du processus d'appel. Tandis que "spawn" crée un nouvel enfant à la racine du graphique.

Ainsi, lorsque vous "forkez" un autre processus, le processus parent attendra que le processus "forké" soit terminé. De plus, chaque exception va remonter de l'enfant au parent et peut être interceptée par le parent.

Un processus "généré" ne bloquera pas le parent, donc la prochaine instruction "yield" est appelée immédiatement. De plus, le processus parent ne pourra pas détecter les exceptions qui se produisent dans le processus "généré".

J'espère que cela a été utile.

26
Alex

Dans les mêmes documents, il est dit:

Lorsque le parent termine l'exécution de son propre corps d'instructions, il attend que toutes les tâches fourchues se terminent avant de revenir.

Disons que nous avons cette configuration où, au milieu du flux d'exécution, nous appelons fetchAll() qui pourrait appeler fork ou 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

Ce que nous voyons, c'est que dans le contexte call la fourchette est non-blocking, Mais call ne va pas se terminer tant que tous ses processus enfants ne seront pas finalisés, puisque call lui-même est un effet bloquant.

Vous ne verriez pas la même chose si vous appelez un fork dans un autre fork, car la fourche elle-même n'est pas bloquante et les processus internes fourchus seraient leak hors des processus externes de la fourche , mais sera conservé dans le contexte de blocage le plus proche. C'est l'essence de attachment to parent.

Ainsi, le parent yield call(forkedProcess) étant de nature bloquante attendra return ou throw resolution Des processus fork enfant.

Ce n'est pas le cas avec spawn(), cependant, puisque le spawn est détaché du processus parent englobant, c'est-à-dire attaché au processus racine, donc le parent local n'a pas à attendre.

J'espère que cela clarifie un peu les choses.

20
Karen Grigoryan