如果我立即放弃,为什么我的叉子会阻塞?

Why does my fork block if I yield it immediately?

我有一个 saga,它假设查询第三方工具来收集 UI 的状态。由于大量的调用,以及我必须如何构建调用树,我正在尝试使用一种方法来启动请求,允许我在拼凑我需要的调用时并行进行十几个,以及加入分叉调用并收集结果的第二种方法。

我的查询方法应该开始调用,如下所示:

* asyncQuery(action, domain, config) {
   let baseUrl;

   if (config && domain) {
      baseUrl = getBaseUrl(config.deployments, domain);
   }  else {
      baseUrl = yield select(selectUrlForDomain(domain));
   }

   return yield fork(this.doManualGetRequest, action.payload.apiPath, baseUrl);
}


 doManualGetRequest(apiPath, baseUrl) {

     const url = buildUrl(basUrl, apiPath);

     const requestPromise = fetch(url, options)
         .then(checkStatus)
         .then(parseJSON)
         .then((data) => ({ data }))
         .catch((err) => ({ err }));
}

这是由负责构建请求树并将每个调用添加到队列的某些逻辑调用的。在调用 joinRequets 之前:

* joinRequests(requestsMap) {
    const results = {}
    const requests = Object.entries(requestsMap)


    join(Object.values(requestsMap));

    for (let i = 0; i < requests.length; i++) {

       const [key, request] = request[i];

       results[key] = request.result();
    }

    return results;
}

经过一些实验后,我发现每次调用 doManualGetRequest 都是阻塞的。具体来说,我可以在我的网络选项卡中看到只有在最后一次调用完成后才进行一次调用,并且我使用打印语句和睡眠来确认在 doManualGetRequest 返回的承诺完成执行之前不会调用新的 fork。

如果我不在 asyncQuery 中生成 fork 命令,而是在 运行 加入命令之前在 joinRequest 中执行生成,我会看到所有查询都以适当的异步方式一次发送出去方式。

为什么在 doManualGetRequest 中让步会导致阻塞行为?

yielding a fork in doManualGetRequest blocks 因为 doManualGetRequest 在 returning 之前等待分叉进程。 这里的文档有点棘手,如果你仔细看你就能找到原因。

来自文档:

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

https://redux-saga.js.org/docs/api/#forkfn-args

因此,如果您在 yield fork 之后的 doManualGetRequest 中有更多代码,那么该代码将在您分叉进程后立即 运行。但是,在 fork 完成(或失败)之前,doManualGetRequest 不会 return

fork 的目的是让您可以附加对异步任务的引用并可能取消它或检查它是否仍在 运行ning。你的情况,你不需要那个功能。 请尝试 spawn

来自文档,spawn(fn, ...args):

Same as fork(fn, ...args) but creates a detached task. A detached task remains independent from its parent and acts like a top-level task. The parent will not wait for detached tasks to terminate before returning and all events which may affect the parent or the detached task are completely independents (error, cancellation).

https://redux-saga.js.org/docs/api/#spawnfn-args