我有一个传奇,应该查询第三方工具来收集UI的状态。由于调用数量众多,而且我必须如何构建调用树,因此我尝试使用一种以fork开始请求的方法,以便在我将所需的调用组合在一起时可以并行创建十几个调用,以及加入分叉呼叫并收集结果的第二种方法。
应该启动调用的我的查询方法如下:
* 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的每个调用都被阻止了。具体来说,我可以在“网络”选项卡中观察到只有在最后一个调用完成之后才进行一次调用,并且我使用了print语句和sleep来确保在doManualGetRequest返回的promise完成执行之前不会调用新的fork。
如果我不是在asyncQuery中不产生fork命令,而是在运行join命令之前在joinRequest中产生yield,我会看到所有查询都以适当的异步方式立即发送出去。
为什么doManualGetRequest中的yield导致阻塞行为?
答案 0 :(得分:1)
yield
在fork
块中插入doManualGetRequest
,因为doManualGetRequest
在等待分叉的过程之后才返回。这里的文档有些棘手,如果您仔细观察,就会发现原因。
从文档中
所有分叉的任务都附加到其父母身上。当父母终止执行自己的指令集时,它将等待所有分叉的任务终止后再返回。
https://redux-saga.js.org/docs/api/#forkfn-args
因此,如果在doManualGetRequest
之后的yield fork
中有更多代码,则该代码将在您分叉该过程后立即运行。但是,doManualGetRequest
会在fork
完成(或失败)之前不会返回。
fork
的目的是使您可以将引用附加到异步任务上,并可能将其取消或检查其是否仍在运行。您的情况下,您不需要该功能。 请改为尝试spawn
。
从文档中, spawn(fn,... args):
与fork(fn,... args)相同,但是创建了一个分离的任务。分离的任务保持独立于其父任务,并像顶级任务一样工作。 父级不会等待分离的任务终止再返回,并且所有可能影响父级或分离任务的事件都是完全独立的(错误,取消)。