promise封装方法

79 阅读1分钟

例子:存在多个图片资源,已有加载函数loadImg,输入url返回一个promise;该promise在图片下载完成时resolve,下载失败则reject。要求并发下载,控制并发数量。

var urls = ["https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/yi-painting1.png", 
            "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/yi-painting2.png",
            "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/yi-painting3.png", 
            "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/yi-painting4.png",
            "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/yi-painting5.png", 
            "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmn6.png", 
            "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmn7.png",
            "https://hexo-blog-1256114407.cos.ap-shenzhen-fsi.myqcloud.com/bpmn8.png", ];

function loadImg(url) 
    { 
        return new Promise((resolve, reject) => 
            {
                const img = new Image();
                img.onload = function() { 
                    console.log("一张图片加载完成"); 
                    resolve(img); 
                };
                img.onerror = function()
                { 
                   reject(new Error('Could not load image at' + url)); 
                 }; 
                img.src = url;
    });

解析:我们可以先请求url中的前limt个,并且请求时使用promise.race()同时请求。其中有一个完成就把当前请求数组中完成的一项,换成未执行请求的其他项。url遍历完成,最后剩下limt个没完成的请求则使用promise.all()来执行。

function limitLoad(urls, handler, limit) 
    { 
        let sequence = [].concat(urls);   // 复制urls
        let promises = sequence.splice(0,limit).map((url,index)=>{
        //promises是一个执行栈,存储了发起请求的promise。splice()改变原数组。
            return handler(url).then(()=>{
            //通过promise.race控制获得最先执行完的index
                return index
            })
        })
        //sequence被截取了一部分作为执行栈,从urls[limit+1]开始迭代执行。
        return sequence.reduce((pCollect,url)=>{
            return pCollect.then(()=>{
                return Promise.race(promises) //得结果index
            }).then((index)=>{
                promises[index] = handler(url).then(()=>index)
            }).catch(err=>console.log(err))
        },Promise.resolve())
        .then(()=>{
            return Promise.all(promises)
        })
    }
    limitLoad(urls, loadImg, 5)
     .then(res => 
     { 
        console.log("图片全部加载完毕"); 
        console.log(res);
     }).catch(err =>
        { console.error(err); });