(面试题)实现一个js并发下载图片

242 阅读1分钟
function downLoad(url = null) {
    return new Promise((res, rej) => {
        let number = Math.random()
        if (number > 0.5) {
            setTimeout(() => {
                res('succ')
            }, 2000);
        } else {
            setTimeout(() => {
                rej('succ')
            }, 2000);
        }
    })

}
/**
 * 
 * @param {*} imgsUrl 下载图片链接
 * @param {*} limit 同时下载数量限制
 * @param {*} downFnPro 下载函数
 * @param {*} againDownLoadLimit 下载失败再次尝试次数
 */
function requestImgs(imgsUrl, limit, downFnPro, againDownLoadLimit) {
    let imgsReq = imgsUrl.map((url) => {
        return {
            exeDownLoad: () => downFnPro(url), downState: false, url
        }
    });
    let tryAgainCount = 0
    let errDownLoad = []//执行出错
    let unExeArr = []//未开始执行
    let paddingExeArr = []//正在执行
    let succExe = []//执行成功

    let run = function () {
        console.log(imgsReq, 'start')
        for (let i = 0; i < imgsReq.length; i++) {
            //未开始执行
            unExeArr = imgsReq.filter(e => e.downState == false)
            //执行中
            paddingExeArr = imgsReq.filter(e => e.downState === 'padding')
            //执行错误
            errDownLoad = imgsReq.filter(e => e.downState === 'error')
            if (paddingExeArr.length < limit && imgsReq[i].downState === false) {
                imgsReq[i].downState = 'padding'
                imgsReq[i].exeDownLoad().then(suc => {
                    // console.log('下载成功')
                    imgsReq[i].downState = true
                    succExe.push(imgsReq[i])
                    run()
                }, err => {
                    // console.log('下载失败')
                    errDownLoad.push(imgsReq[i])
                    imgsReq[i].downState = 'error'
                    run()
                }).catch((e) => {
                    errDownLoad.push(imgsReq[i])
                    imgsReq[i].downState = 'error'
                    // console.log('下载失败catch')
                    run()
                })
                run()
            }
        }
        // console.log({ errDownLoad, unExeArr, paddingExeArr })
        if (errDownLoad.length > 0 && unExeArr.length == 0 && paddingExeArr.length == 0) {
            unExeArr = [...errDownLoad].map(e => {
                e.downState = false
            })
            if (tryAgainCount < againDownLoadLimit) {
                run()
            } else {
                for (let i = 0; i < errDownLoad.length; i++) {
                    console.log(errDownLoad[i].url + ':' + againDownLoadLimit + '次尝试后下载失败!请刷新重试')
                }
                // console.log(imgsReq, 'end')
                return
            }
            tryAgainCount++
        } else if (errDownLoad.length == 0 && unExeArr.length == 0 && paddingExeArr.length == 0) {
            // console.log(imgsReq, 'end')
            console.log('全部下载成功', imgsReq)
            return
        }
    }
    run()
}