JS事件循环问题

我的需求:
我的需求可以简单描述为,对一个大文件进行分片切割上传。我实现的思路为,
对一个大文件,按照设定的chunksSize切分为N=file.size/chunkSize块,
然后循环创建N个读流读取每个分片的内容,然后发起N个http.request的Post请求去上传文件。
代码如下(说明:upload函数用来根据分块的个数n,计算每块起始标志位和终止标识位,并调用senddataPromise函数对每片进行操作)
functionupload(username,filepath,file_id,filelength,n,alreadychunks,chunkSize){
returnnewPromise(function(resolve,reject){
varstart=0,end=0;
varpromiseall=[];
for(letcurindex=0;curindexif(filelength-start<=chunkSize){
end=filelength-1;
}else{
end=start+chunkSize-1;//因读取时包含start和end位
}
if(alreadychunks.indexOf(curindex)==-1){
letoptions={
flags:'r',
highWaterMark:chunkSize,
start:start,
end:end
};
promiseall.push(senddataPromise(filepath,options,username,file_id,curindex,end-start+1));
}
start=end+1;
}
lettimer=setInterval(()=>{
if(promiseall.length==n){
clearInterval(timer);
Promise.all(promiseall).then(values=>{
console.log(values);
console.log("alldone");
resolve(true)
}).catch(err=>{
console.log(err);
reject(err);
})
}
},500)
})
}
senddataPromise函数是对第i块分片创建读流读取内容,并调用doapost函数发送到后端
functionsenddataPromise(path,options,username,summary,curindex,length){
returnnewPromise(function(resolve,reject){
letreadSteam=fs.createReadStream(path,options);
readSteam.on("data",(chunk)=>{
console.log("第"+curindex+"块JSON开始")
letchunkjson=JSON.stringify(chunk);
console.log("第"+curindex+"块JSON结束")
lettempcell={
data:chunkjson,
n:curindex,
file_id:summary,
username:username,
length:length
};
chunk=null;
chunkjson=null;
doapost(tempcell).then(values=>{
resolve(values)
}).catch(err=>{
reject(err);
});
})
})
}
doapost函数发起post请求发送分片数据
functiondoapost(data){
returnnewPromise(function(resolve,reject){
leti=data.n;
console.log("第"+i+"份请求准备发出")
letcontents=queryString.stringify(data);
data=null;
letoptions={
host:"localhost",
path:"/nodepost/",
port:8000,
method:'POST',
headers:{
'Content-Type':'application/x-www-form-urlencoded',
'Content-Length':contents.length
}
};
letreq=http.request(options,function(res){
console.log("第"+i+"份请求返回数据")
res.on("data",function(chunk){
console.log(chunk.toString());
});
res.on("end",function(d){
resolve("end");
});
res.on("error",function(e){
reject(e);
})
});
req.write(contents);
req.end();
contents=null;
console.log("第"+i+"份请求已发出")
})
}
我的问题:
按照正常的思路,因为读取文件内容为异步操作,后面发送请求也为异步操作,所以
也就是说会出现对于n个分片,读取数据已经读取了p片,并且已经有q(**q已经完成上传完成返回数据的情况,但是现在问题是,***发现并没有分片上传完返回数据的
情况出现,都是在n个分片读取完成后,才开始统一执行分片内容上传操作***
图片如下:(由于图片无法上传,我把程序运输出拷贝一下)
{
kind:'upload',
username:'moran999',
filepath:'F:/my_upload_test/NowTest.pdf',
file_id:'-196987878-472217752177633040957425519',
alreadychunks:[],
chunkSize:1048576,
n:9}
第0块JSON开始
第0块JSON结束
第0份请求准备发出
第0份请求已发出
第1块JSON开始
第1块JSON结束
第1份请求准备发出
第1份请求已发出
第2块JSON开始
第2块JSON结束
第2份请求准备发出
第2份请求已发出
第3块JSON开始
第3块JSON结束
第3份请求准备发出
第3份请求已发出
第5块JSON开始
第5块JSON结束
第5份请求准备发出
第5份请求已发出
第4块JSON开始
第4块JSON结束
第4份请求准备发出
第4份请求已发出
第6块JSON开始
第6块JSON结束
第6份请求准备发出
第6份请求已发出
第8块JSON开始
第8块JSON结束
第8份请求准备发出
第8份请求已发出
第7块JSON开始
第7块JSON结束
第7份请求准备发出
第7份请求已发出
第8份请求返回数据
moran999
第4份请求返回数据
moran999
第6份请求返回数据
moran999
第1份请求返回数据
moran999
第2份请求返回数据
moran999
第0份请求返回数据
moran999
第3份请求返回数据
moran999
第7份请求返回数据
moran999
第5份请求返回数据
moran999
['end','end','end','end','end','end','end','end','end']
alldone
可以看到其POST数据的发出并不是和读流无关的,即任何一个POST都不会发出,
直到到所有的读流读取完数据,想问一下各位码友是什么原因尼??因为正常
理解下当第i个读流读的时候,前面已经读取完内容的读流完全可以进行post操作
了啊,但实际上并没有。
之所以会问这个问题是因为当我输入的文件比较大时,他执行到《第12块JSON开始时,
就内存溢出了》,而如果程序是post不用等待所有的读流读完时,当有一部分post执行完之后,其对应的数据就被回收了,释放相应的内存,就不会出现内存溢出了。
人到中年有点甜
浏览 336回答 2
2回答

噜噜哒

不是呀,这个是正常的呀,你看第1份post已经发出是在第2块JSON开始之前呀,post发出和http.requset并列,JSON开始是读完文件之后,所以发送数据是在文件读完之前,只是读后面块的时候前面的请求还没有执行完,所以并没有第n份数据返回。网络延时比读取文件大的多,所以文件读完之前不会返回呀。感觉,这段代码不至于在12的时候内存溢出呀。nodejs上传文件的话用管道更好一点儿吧。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript