Promise實現多圖預加載

Promise正如它的中文意思「承諾」同樣,保存着將來會發生事件(通常爲異步操做)。Promise避免了「回調地獄」,寫法更加接近同步操做。說到同步,我更加喜歡async、await,它們書寫更貼近同步操做。數組

圖片加載每每是異步的,若是有操做須要等到全部的圖片加載完以後再執行,這時候就須要不斷的監聽全部圖片的加載狀況。異步

ES5async

利用ES5實現多圖預加載,能夠經過計數器判斷有多少圖片加載完成。函數

var count = 0,    // 計數器
    imgs = [];

/*
* (Array)source 圖片url
* (Fun)cb 回調
*/
function preLoadImg(source, cb) { source.forEach(function(url, i) { imgs[i] = new Image(); imgs[i].onload = function() { if(++count === source.length) { cb && cb(); } } imgs.src = url; }) }

ES6this

ES6原生提供了Promise對象,接下來用Promise改寫上面的代碼。url

    // 預處理圖片
    function preLoadImg(source){
        let pr = [];
        source.forEach(url => {// 預加載圖片
            let p = loadImage(url)
                    .then(img => this.images.push(img))
                    .catch(err => console.log(err))
            pr.push(p);
        })

        // 圖片所有加載完
        Promise.all(pr)
                .then(() => {
                    // do sth
                });

    }
    // 預加載圖片
    function loadImage(url) {
        return new Promise((resolve, reject) => {
            let img = new Image();
            img.onload = () => resolve(img);
            img.onerror = reject;
            img.src = url;
        })
    }

Promise其實是將回調操做獨立出來,當Promise狀態從pending(進行中)改成resolved(已完成),then註冊的函數就會被執行,若是狀態從pending改成rejected(已失敗),就會被catch捕獲。spa

這裏向Promise.all傳入了一個數組(能夠不是數組,具備iterator接口對象都可以,但返回的成員都必須是Promise實例,若是不是Promise實例,也會調用Promise.resolve轉化爲Promise實例),數組中的Promise狀態均爲resolved,Promise.all的狀態纔會是resolved,不然Promise.all的狀態爲rejected。也就是說,當全部圖片加載完成後,纔會執行then中的函數。code

可是,若是參數中的Promise實例本身有定義catch方法,那麼當rejected的時候,就會被本身的catch捕獲,catch方法執行完後,是會返回一個新的,狀態爲resolve的Promise實例,所以,傳給Promise.all的是這個新的,狀態爲resolve的Promise。爲了防止有圖片加載失敗,阻塞後續操做,爲每個p添加catch,捕獲reject,Primise.all就接受不到了。對象

相關文章
相關標籤/搜索