如果我立即屈服,为什么叉会挡住?

时间:2018-08-16 13:28:27

标签: javascript asynchronous generator redux-saga

我有一个传奇,应该查询第三方工具来收集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导致阻塞行为?

1 个答案:

答案 0 :(得分:1)

yieldfork块中插入doManualGetRequest,因为doManualGetRequest 在等待分叉的过程之后才返回。这里的文档有些棘手,如果您仔细观察,就会发现原因。

从文档中

  

所有分叉的任务都附加到其父母身上。当父母终止执行自己的指令集时,它将等待所有分叉的任务终止后再返回。

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

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

fork的目的是使您可以将引用附加到异步任务上,并可能将其取消或检查其是否仍在运行。您的情况下,您不需要该功能。 请改为尝试spawn

从文档中, spawn(fn,... args)

  

与fork(fn,... args)相同,但是创建了一个分离的任务。分离的任务保持独立于其父任务,并像顶级任务一样工作。 父级不会等待分离的任务终止再返回,并且所有可能影响父级或分离任务的事件都是完全独立的(错误,取消)。

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