我使用 got.stream 下載檔案并通過流式傳輸將其發送到客戶端。
我想監控在任何給定時刻有多少下載,為此我需要知道下載何時結束以更新計數器。
const stream = require('stream');
const { promisify } = require('util');
const pipeline = promisify(stream.pipeline);
const got = require('got');
let currentDownloadsStream = 0;
app.get('download', async (req, res) => {
currentDownloadsStream ;
const downloader = got.stream(url);
return pipeline(downloader, res)
.finally(() => currentDownloadsStream--)
});
問題是如果客戶端在中間取消了下載,finally 方法就永遠不會被呼叫,就好像promise 永遠留在記憶體中,永遠不會被解決。
我試圖添加
res.on('close', () => {
downloader.destroy();
})
但這也無濟于事,如果我在瀏覽器中取消下載,則不會觸發此事件。
如何判斷客戶端是否在下載完成之前停止了下載?
nodejs v16.17.0
編輯:感謝@jfriend00幫助我發現問題,問題是由webpack開發服務器引起的,在生產中事件是正常發出的。
uj5u.com熱心網友回復:
問題是如果客戶端在中間取消了下載,finally 方法就永遠不會被呼叫,就好像promise 永遠留在記憶體中,永遠不會被解決。
如果瀏覽器下載真的取消了,我無法在 Chrome 或者 Edge 和 nodejs 16.14.2 版本中重現這個問題。當我開始大量下載并通過單擊 Chrome 下載欄中的“取消”選項取消下載時,我立即收到一堆事件并看到管道承諾拒絕并呼叫.finally()。
我想知道您是否實際上沒有取消瀏覽器中的下載。在 Chrome 和 Edge 中(我沒有嘗試其他瀏覽器),僅關閉下載的選項卡或視窗不會停止下載。您必須物理取消下載或退出整個瀏覽器并回答“是”以停止下載。
以下是我在 Chrome 和 Edge 中手動取消下載時收到的事件:
- 關閉
res流上的事件 - 下載器上的錯誤事件:ERR_STREAM_PREMATURE_CLOSE
- 下載器流上的關閉事件
.catch()關于管道承諾:ERR_STREAM_PREMATURE_CLOSE.finally()關于管道承諾- 下載器流上的錯誤事件:ECONNRESET
在 Edge 瀏覽器中,如果我完全退出瀏覽器并對提示回答“是”以取消“正在進行”下載,那么我會得到:
- 關閉
res流上的事件 - 下載器上的錯誤事件:ERR_STREAM_PREMATURE_CLOSE
- 下載器流上的關閉事件
.catch()關于管道承諾.finally()關于管道承諾- 下載器流上的錯誤事件:ECONNRESET
僅供參考,我使用此 URL 進行大型下載:“http://speedtest-sgp1.digitalocean.com/5gb.test”來自該站點:https ://testfiledownload.com/作為大型下載的來源。
這是我的測驗代碼:
const express = require('express');
const stream = require('stream');
const { pipeline } = require('node:stream/promises');
const got = require('got');
const app = express();
const url = "http://speedtest-sgp1.digitalocean.com/5gb.test";
let currentDownloadsStream = 0;
app.get('/download', async (req, res) => {
currentDownloadsStream ;
const downloader = got.stream(url);
downloader.on('end', () => {
console.log("end event on downloader");
}).on('close', () => {
console.log("close event on downloader");
}).on('error', err => {
console.log("error event on downloader");
console.log(err);
});
res.on('finish', () => {
console.log("finish event");
}).on('end', () => {
console.log("end event on res");
}).on('prefinish', () => {
console.log("prefinish eventon res");
}).on('close', () => {
console.log("close event on res");
}).on('error', err => {
console.log("error event on res");
console.log(err);
});
pipeline(downloader, res).then(result => {
console.log(".then() called");
}).catch(err => {
console.log(".catch() called");
console.log(err);
}).finally(() => {
console.log(".finally() called");
currentDownloadsStream--;
})
});
app.listen(80);
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/510354.html
標籤:节点.js表示溪流
下一篇:NodeJS陣列未填滿
