Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/407.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何知道提取何时结束而不锁定主体流?_Javascript_Fetch Api_Whatwg Streams Api - Fatal编程技术网

Javascript 如何知道提取何时结束而不锁定主体流?

Javascript 如何知道提取何时结束而不锁定主体流?,javascript,fetch-api,whatwg-streams-api,Javascript,Fetch Api,Whatwg Streams Api,我正在向API发出请求,但是他们的服务器只允许一定数量的活动连接,所以我想限制正在进行的获取的数量。就我而言,只有当HTTP响应主体到达客户端时,才会完成(而不是进行中)提取 我想创建一个这样的抽象: const fetchlimitor=新的fetchlimitor(maxConnections); fetchlimitor.fetch(url,选项);//返回与fetch()相同的内容 这将使事情简单得多,但似乎无法知道其他代码使用的流何时结束,因为流在读取时被锁定。可以使用Readabl

我正在向API发出请求,但是他们的服务器只允许一定数量的活动连接,所以我想限制正在进行的获取的数量。就我而言,只有当HTTP响应主体到达客户端时,才会完成(而不是进行中)提取

我想创建一个这样的抽象:

const fetchlimitor=新的fetchlimitor(maxConnections);
fetchlimitor.fetch(url,选项);//返回与fetch()相同的内容

这将使事情简单得多,但似乎无法知道其他代码使用的流何时结束,因为流在读取时被锁定。可以使用
ReadableStream.tee()
将流拆分为两个,使用一个流并将另一个流返回给调用者(也可能使用它构造
响应
),但这会降低性能,对不对?

因为
fetch
使用承诺,您可以利用这一点来创建一个简单的队列系统

这是我以前用于排队基于承诺的东西的方法。它通过创建一个
Promise
,然后将其解析器添加到一个数组中,从而对项目进行排队。当然,在该承诺得到解决之前,
wait
会阻止任何后续承诺被调用

我们所要做的就是在完成后开始下一次提取,只需抓取下一个解析器并调用它。承诺解决了,然后
fetch
开始

最重要的是,由于我们实际上并不使用
获取
结果,因此不必担心必须
克隆
或任何东西……我们只需将其原封不动地传递,以便您可以在以后的
然后
或其他事情中使用它

*编辑:由于在fetch承诺解析后body仍在流式传输,因此我添加了第三个选项,以便您可以传入body类型,并让FetchLimiter为您检索和解析body

所有这些都返回了一个最终通过实际内容解决的承诺

那样的话,你就可以为自己解析身体了。我这样做是为了它将返回一个
[响应,数据]
数组,这样您仍然可以检查响应代码、标题等内容

因此,如果您需要执行更复杂的操作,例如根据响应代码对主体进行不同的解析方法,您甚至可以传入回调或在
wait
中使用的内容

示例

我添加了注释以指示
fetchlimitor
代码的开始和结束位置……其余的只是演示代码

它使用了一个伪
获取
,并使用了一个setTimeout,它将在0.5-1.5秒之间解析。它将立即启动前三个请求,然后活动将满,并等待一个请求得到解决

发生这种情况时,您将看到承诺已解决的注释,然后队列中的下一个承诺将启动,然后您将看到
中的
然后
中的
for
循环解决。我添加了
,然后添加了
,这样您就可以看到事件的顺序

(函数(){
const fetch=(资源,初始化)=>新承诺((解析,拒绝)=>{
console.log('starting'+资源);
设置超时(()=>{
console.log('-resolving'+资源);
解决(资源);
},500+1000*Math.random());
});
函数fetchlimitor(){
this.queue=[];
此参数为0;
此.maxActive=3;
this.fetchFn=fetch;
}
FetchLimiter.prototype.fetch=异步函数(资源、初始化、respType){
//如果处于最大活动状态,则通过添加承诺将下一个请求排队
//并将解析器放入“队列”数组中。
如果(this.active>=this.maxActive){
等待新的承诺(解决=>{
this.queue.push(resolve);//push,添加到数组末尾
});
}
this.active++;//在我们即将开始提取时,递增active
const resp=wait this.fetchFn(资源,init);
让数据;
if(['arrayBuffer','blob','json','text','formData'].indexOf(respType)>=0)
数据=等待响应[respType]();
this.active-->//一旦完成提取,就减少活动
this.checkQueue();//从队列开始下一次提取的时间
return[resp,data];//从fetch返回值
};
FetchLimiter.prototype.checkQueue=函数(){
if(this.activeconsole.log('-.then'+x));
}

})();
您可以只对调用方构造一个假的
响应
,控制调用方将使用的流。@Bergi,然后将真正的流导入其中?听起来是个好主意,但我不确定这会对性能产生什么影响。我非常确定这会比
tee()
ing流,甚至
clone()
ing响应更好。当然,如果你足够关心的话,你必须进行基准测试。另一种方法是只向
fetchLimiter
传递一个回调函数,该函数将处理响应,其结果将等待排队。这是处理异步“资源”使用的标准方法。谢谢,但这并不能解决问题。“我不能100%确定当承诺解决时,身体是否仍在流动……”是的,除非身体是空的或真的很小。
fetch()
返回的承诺将在头到达时立即解析。“但是,如果这是一个问题,您可以使用一个Body mixin方法,如
blob
text
json
,直到完整解析Body内容后才能解决。”