在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 問答/HTML/ JS事件循環(huán)問題

JS事件循環(huán)問題

我的需求:

 我的需求可以簡單描述為,對一個大文件進行分片切割上傳。我實現(xiàn)的思路為,
 對一個大文件,按照設(shè)定的chunksSize切分為N = file.size/chunkSize塊,
 然后循環(huán)創(chuàng)建N個讀流讀取每個分片的內(nèi)容,然后發(fā)起N個http.request的Post請求去上傳文件。
 

代碼如下
(說明: upload函數(shù)用來根據(jù)分塊的個數(shù)n,計算每塊起始標志位和終止標識位,并調(diào)用senddataPromise函數(shù)對每片進行操作)

function  upload(username,filepath,file_id,filelength,n,alreadychunks,chunkSize) {
    return new Promise(function (resolve,reject) {
            var start = 0,end = 0;
            var promiseall = [];
            for (let curindex = 0;curindex < n;curindex++) {
                if(filelength - start <= chunkSize) {
                    end  =  filelength - 1;
                }else {
                    end = start+chunkSize - 1; // 因讀取時包含start和end位
                }
                if(alreadychunks.indexOf(curindex) == -1) {
                    let options = {
                        flags: 'r',
                        highWaterMark: chunkSize,
                        start: start,
                        end: end
                    };
                    promiseall.push(senddataPromise(filepath,options,username,file_id,curindex,end-start+1));
                }
                start = end + 1;
            }
            let timer = setInterval(() => {
                if(promiseall.length == n) {
                    clearInterval(timer);
                    Promise.all(promiseall).then(values=>{
                        console.log(values);
                        console.log("all done");
                        resolve(true)
                    }).catch(err => {
                        console.log(err);
                        reject(err);
                    })
                }
            },500)
    })
}

senddataPromise函數(shù)是對第i塊分片創(chuàng)建讀流讀取內(nèi)容,并調(diào)用doapost函數(shù)發(fā)送到后端

function senddataPromise(path,options,username,summary,curindex,length) {
    return new Promise(function (resolve,reject) {
        let readSteam = fs.createReadStream(path,options);
        readSteam.on("data",(chunk) => {
            console.log("第"+curindex+"塊 JSON開始")
            let chunkjson = JSON.stringify(chunk);
            console.log("第"+curindex+"塊 JSON結(jié)束")
            let tempcell = {
                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函數(shù)發(fā)起post請求發(fā)送分片數(shù)據(jù)

function  doapost(data) {
    return new Promise(function (resolve,reject) {
        let i = data.n;
        console.log("第"+i+"份請求準備發(fā)出")
        let contents = queryString.stringify(data);
        data = null;
        let options = {
            host: "localhost",
            path: "/nodepost/",
            port: 8000,
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
                'Content-Length': contents.length
            }
        };
        let req = http.request(options, function (res) {
            console.log("第"+i+"份請求返回數(shù)據(jù)")
            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+"份請求已發(fā)出")
    })
}

我的問題:

  按照正常的思路,因為讀取文件內(nèi)容為異步操作,后面發(fā)送請求也為異步操作,所以
  也就是說會出現(xiàn)對于n個分片,讀取數(shù)據(jù)已經(jīng)讀取了p片,并且已經(jīng)有q(**q < p**)片
  已經(jīng)完成上傳完成返回數(shù)據(jù)的情況,但是現(xiàn)在問題是,***發(fā)現(xiàn)并沒有分片上傳完返回數(shù)據(jù)的
  情況出現(xiàn),都是在n個分片讀取完成后,才開始統(tǒng)一執(zhí)行分片內(nèi)容上傳操作***
  圖片如下:(由于圖片無法上傳,我把程序運輸出拷貝一下)
{ 
 kind: 'upload',
username: 'moran999',
filepath: 'F:/my_upload_test/NowTest.pdf',
file_id: '-196987878-472217752177633040957425519',
alreadychunks: [],
chunkSize: 1048576,
n: 9 }
第0塊 JSON開始
第0塊 JSON結(jié)束
第0份請求準備發(fā)出
第0份請求已發(fā)出
第1塊 JSON開始
第1塊 JSON結(jié)束
第1份請求準備發(fā)出
第1份請求已發(fā)出
第2塊 JSON開始
第2塊 JSON結(jié)束
第2份請求準備發(fā)出
第2份請求已發(fā)出
第3塊 JSON開始
第3塊 JSON結(jié)束
第3份請求準備發(fā)出
第3份請求已發(fā)出
第5塊 JSON開始
第5塊 JSON結(jié)束
第5份請求準備發(fā)出
第5份請求已發(fā)出
第4塊 JSON開始
第4塊 JSON結(jié)束
第4份請求準備發(fā)出
第4份請求已發(fā)出
第6塊 JSON開始
第6塊 JSON結(jié)束
第6份請求準備發(fā)出
第6份請求已發(fā)出
第8塊 JSON開始
第8塊 JSON結(jié)束
第8份請求準備發(fā)出
第8份請求已發(fā)出
第7塊 JSON開始
第7塊 JSON結(jié)束
第7份請求準備發(fā)出
第7份請求已發(fā)出
第8份請求返回數(shù)據(jù)
moran999
第4份請求返回數(shù)據(jù)
moran999
第6份請求返回數(shù)據(jù)
moran999
第1份請求返回數(shù)據(jù)
moran999
第2份請求返回數(shù)據(jù)
moran999
第0份請求返回數(shù)據(jù)
moran999
第3份請求返回數(shù)據(jù)
moran999
第7份請求返回數(shù)據(jù)
moran999
第5份請求返回數(shù)據(jù)
moran999
[ 'end', 'end', 'end', 'end', 'end', 'end', 'end', 'end', 'end' ]
all done
  可以看到其POST數(shù)據(jù)的發(fā)出并不是和讀流無關(guān)的,即任何一個POST都不會發(fā)出,
  直到到所有的讀流讀取完數(shù)據(jù),想問一下各位碼友是什么原因尼??因為正常
  理解下當(dāng)?shù)趇個讀流讀的時候,前面已經(jīng)讀取完內(nèi)容的讀流完全可以進行post操作
  了啊,但實際上并沒有。

  之所以會問這個問題是因為當(dāng)我輸入的文件比較大時,他執(zhí)行到《第12塊 JSON開始時,
  就內(nèi)存溢出了》,而如果程序是post不用等待所有的讀流讀完時,當(dāng)有一部分post執(zhí)行完之后,其對應(yīng)的數(shù)據(jù)就被回收了,釋放相應(yīng)的內(nèi)存,就不會出現(xiàn)內(nèi)存溢出了。
  
  
  
回答
編輯回答
淺時光

不是呀,這個是正常的呀,你看 第1份 post已經(jīng)發(fā)出 是在第2塊JSON開始之前呀,post發(fā)出和 http.requset并列,JSON開始是讀完文件之后,所以發(fā)送數(shù)據(jù)是在 文件讀完之前,只是讀后面塊的時候前面的請求還沒有執(zhí)行完,所以并沒有 第n份數(shù)據(jù)返回。 網(wǎng)絡(luò)延時比讀取文件大的多,所以文件讀完之前不會返回呀。

感覺,這段代碼不至于在 12 的時候內(nèi)存溢出呀。

nodejs 上傳文件的話用 管道 更好一點兒吧。

2018年4月16日 10:23
編輯回答
陌璃

@zonxin 所說,代碼和你設(shè)想的大致相同。

補充為什么第12塊就已經(jīng)溢出

  1. let chunkjson = JSON.stringify(chunk);把本來1MBuffer轉(zhuǎn)成和數(shù)組樣式的字符串[104,101,...],內(nèi)存漲了x倍(就不用說后面還有個queryString.stringify)。
  2. nodejs內(nèi)存受V8限制(64位系統(tǒng)下約為1.4GB,32位系統(tǒng)下約為0.7GB,Buffer除外),而樓主剛好把Buffer轉(zhuǎn)成string。
  3. 沒用pipe(轉(zhuǎn)成string也沒法用),以至于發(fā)送過的字節(jié)還保留在內(nèi)存,直到完整是字符串發(fā)送完,而完整的一塊缺有卻有x*1M。
2017年10月27日 05:41
編輯回答
心夠野
  • 網(wǎng)絡(luò)延遲肯定是大于你本地的io速率的,所以請求在所有文件分塊被讀完之前沒有返回是正常的
  • 你這里使用了readable stream,但是每一次都會創(chuàng)建一個新的steram并且還會完整地讀這個大文件,我覺的在第一點的基礎(chǔ)上,這是造成溢出的主要原因
  • 分片上傳在nodejs做的話,使用stream的管道做組合好一些吧,大體思路就是先創(chuàng)建一個readable stream,之后在pipe中傳入分片和上傳邏輯,這么做肯定比使用stream.on('data')要好,因為你還可以和別的stream對象做組合,比如http的res等等。
  • nodejs中的readable stream本身就是一種分片讀取技術(shù),所以在其之上增加額外的變換邏輯就行了
2017年5月25日 08:47