简体   繁体   English

加载所有图像后解决承诺

[英]Resolve promise when all images are loaded

I was preloading images with the following code: 我正在使用以下代码预加载图像:

    function preLoad() {
        var deferred = $q.defer();
        var imageArray = [];
        for (var i = 0; i < $scope.abbreviations.length; i++) {
            imageArray[i] = new Image();
            imageArray[i].src = $scope.abbreviations[i].imgPath;
        }
        imageArray.forEach.onload = function () {
            deferred.resolve();
            console.log('Resolved');
        }
        imageArray.forEach.onerror = function () {
            deferred.reject();
            console.log('Rejected')
        }
        return deferred.promise;
    }
    preLoad();

I thought images were all loading correctly because I could see the 'Resolved' log. 我认为图像都已正确加载,因为我可以看到“已解决”日志。

Later somebody pointed out that the code above doesn't guarantee that all images are loaded before resolving the promise. 后来有人指出,上面的代码不能保证在解决承诺之前已加载所有图像。 In fact, only the first promise is resolved. 实际上,只有第一个诺言得以解决。

I was advised to use $q.all applied to an array of promises instead. 建议我将$q.all应用于一个promise数组。 This is the resulting code: 这是结果代码:

    function preLoad() {
        var imageArray = [];
        var promises;
        for (var i = 0; i < $scope.abbreviations.length; i++) {
            imageArray[i] = new Image();
            imageArray[i].src = $scope.abbreviations[i].imgPath;
        };

        function resolvePromises(n) {
            return $q.when(n);
        }
        promises = imageArray.map(resolvePromises);
        $q.all(promises).then(function (results) {
            console.log('array promises resolved with', results);
        });
    }
    preLoad();

This works, but I want to understand: 这可行,但我想了解:

  1. what's happening in each function; 每个功能发生了什么;
  2. why I need $q.all to make sure all images are loaded before resolving the promises. 为什么我需要$q.all来确保在解决承诺之前已加载所有图像。

The relevant docs are somewhat cryptic. 相关文档有些含糊。

Check out this plunkr . 看看这个笨蛋

Your function: 您的功能:

function preLoad() {

    var promises = [];

    function loadImage(src) {
        return $q(function(resolve,reject) {
            var image = new Image();
            image.src = src;
            image.onload = function() {
              console.log("loaded image: "+src);
              resolve(image);
            };
            image.onerror = function(e) {
              reject(e);
            };
        })
    }

    $scope.images.forEach(function(src) {
      promises.push(loadImage(src));
    })

    return $q.all(promises).then(function(results) {
        console.log('promises array all resolved');
        $scope.results = results;
        return results;
    });
}

The idea is very similar to Henrique's answer, but the onload handler is used to resolve each promise, and onerror is used to reject each promise. 这个想法与Henrique的答案非常相似,但是onload处理程序用于解决每个诺言,而onerror用于拒绝每个诺言。

To answer your questions: 要回答您的问题:

1) Promise factory 1)承诺工厂

$q(function(resolve,reject) { ... })  

constructs a Promise. 构造一个承诺。 Whatever is passed to the resolve function will be used in the then function. 传递给resolve函数的所有内容都将在then函数中使用。 For example: 例如:

$q(function(resolve,reject) {
     if (Math.floor(Math.random() * 10) > 4) {
         resolve("success")
     }
     else {
         reject("failure")
     }
}.then(function wasResolved(result) {
    console.log(result) // "success"
}, function wasRejected(error) {
    console.log(error) // "failure"
})

2) $q.all is passed an array of promises, then takes a function which is passed an array with the resolutions of all the original promises. 2)$ q.all被传递了一个promise数组, then接受了一个函数,该函数被传递了一个具有所有原始promise分辨率的数组。

I'm not used to angular promise library, but the idea is as follows: 我不习惯角度承诺库,但是想法如下:

function getImagePromise(imgData) {
    var imgEl = new Image();
    imgEl.src = imgData.imgPath;

    return $q(function(resolve, reject){
        imgEl.addEventListener('load', function(){
            if ((
                   'naturalHeight' in this 
                    && this.naturalHeight + this.naturalWidth === 0
                ) 
                || (this.width + this.height == 0)) {
                reject(new Error('Image not loaded:' + this.src));
            } else {
                resolve(this);
            }
        });

        imgEl.addEventListener('error', function(){
            reject(new Error('Image not loaded:' + this.src));
        });
    })
}

function preLoad() {
    return $q.all($scope.abbreviations.map(getImagePromise));
}

// using
preLoad().then(function(data){
    console.log("Loaded successfully");
    data.map(console.log, console);
}, function(reason){
    console.error("Error loading: " + reason);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM