SOURCE

const chunkSize = 15;
let startWith = 0;
let endWith = 1024 * 1024 * chunkSize;
let num = 0;
const url = 'https://jf-open-test-1301446188.cos.ap-guangzhou.myqcloud.com/media/S/22/0824/e2JJNIspQnK6xsaVRETV1jvk.mp4';

function request(url, total = null) {
    num++;
    endWith = 15888249;
    const headers = {
        'If-Range': new Date(),
        Range: `bytes=${startWith}-${endWith * num}`,
        'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
    };

    const req = fetch(url, {
        headers
    })
        .then(res => {
            console.log('resp');
            console.log(res.headers.get("content-range"))
            return res.blob();
        });
    startWith = endWith;
    return req;
}

function download(fileName, blob) {
    console.log("download");
    console.log(blob)
    if ("download" in document.createElement("a")) {
        //支持a标签download的浏览器
        const link = document.createElement("a"); //创建a标签
        link.download = fileName; //a标签添加属性
        link.style.display = "none";
        link.href = URL.createObjectURL(blob);
        document.body.appendChild(link);
        link.click(); //执行下载
        URL.revokeObjectURL(link.href); //释放url
        document.body.removeChild(link); //释放标签
    } else {
        //其他浏览器
        navigator.msSaveBlob(blob, fileName);
    }
}

// 任务队列
const taskQueueNumber = 10;
// 块大小
// const chunkSize = 3;



const queue = Array(taskQueueNumber).fill(() =>
    (task, callback) => {
        const work = new Worker('./worker.js', { name: 'myWorker' });
        work.postMessage(task)
        work.onmessage = (e) => {
            console.log(`主进程收到了子进程发出的信息:${e.data.msg}`);
            console.log(e.data.obj);
            callback(e.data);
            // 主进程收到了子进程发出的信息:你好,我是子进程!
            work.terminate();
        };
    }
).map(o => o());

async function download(url, maxSize = null, num = 0) {
    console.log('download', maxSize)
    const getHeaders = ((initNum = 0) =>
        (num = initNum) => {
            console.log(num);
            const chunk = chunkSize * 1024 * 1024;

            let headers = {
                'If-Range': new Date(),
                Range: `bytes=0-${chunk}`,
                'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
            };

            if (num) {
                const startWith = chunk * num + 1;
                const endWith = chunk * (num + 1);
                headers = {
                    'If-Range': new Date(),
                    Range: `bytes=${startWith}-${endWith}`,
                    'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
                };
            }
            initNum++;
            return headers;
        }
    )()

    let res = null;
    console.log('down')
    if (!maxSize) {
        res = await fetch(url, {
            headers: {
                'If-Range': new Date(),
                Range: `bytes=0-1`,
                'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
            }
        });
        console.log(res, 'res');
        const range = res.headers.get("content-range");
        console.log(range, 'res', range.split('/').pop());
        maxSize = range.split('/').pop();
        if (maxSize) {
            download(url, maxSize, num);
            return;
        }
    }
    const totalSize = maxSize / 1024 / 1024;
    console.log(totalSize)
    console.log(totalSize / chunkSize)
    const queueNum = Math.ceil(totalSize / chunkSize);

    const reqs = Array(queueNum).fill(null).map((o, i) => {
        // const resp = await fetch(url, {
        //     headers: getHeaders()
        // });
        // return resp;
        return new Promise((resolve) => {
            const work = new Worker('./worker.js', { name: `myWorker_${i}` });
            work.postMessage({
                url,
                headers: getHeaders(),
                index: i
            });
            work.onmessage = (e) => {
                console.log(`主进程收到了子进程发出的信息`);
                console.log(e.data);
                resolve({ data: e.data, i });
                work.terminate();
            };
        })
    })

    res = await Promise.all(reqs);
    res = res.sort((o1, o2) => o1.index - o2.index).map(o => o.data);
    console.log(res, 'res');

    const blob = new Blob(res);

    if ("download" in document.createElement("a")) {
        //支持a标签download的浏览器
        const link = document.createElement("a"); //创建a标签
        link.download = `${Date.now()}.mp4`
        // fileName; //a标签添加属性
        link.style.display = "none";
        link.href = URL.createObjectURL(blob);
        document.body.appendChild(link);
        link.click(); //执行下载
        URL.revokeObjectURL(link.href); //释放url
        document.body.removeChild(link); //释放标签
    } else {
        //其他浏览器
        navigator.msSaveBlob(blob, fileName);
    }
}

download('me url', null, null);
console 命令行工具 X clear

                    
>
console