javascript 加载所有图像时解决承诺
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32214924/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Resolve promise when all images are loaded
提问by U r s u s
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.
This is the resulting code:
我被建议改用$q.all
应用于一系列承诺。这是结果代码:
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:
这有效,但我想了解:
- what's happening in each function;
- why I need
$q.all
to make sure all images are loaded before resolving the promises.
- 每个函数中发生了什么;
- 为什么我需要
$q.all
确保在解决承诺之前加载所有图像。
The relevant docsare somewhat cryptic.
在相关的文档有些神秘。
回答by ShaharZ
Check out this plunkr.
看看这个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. For example:
构造一个 Promise。传递给resolve
函数的任何内容都将在函数中使用then
。例如:
$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 被传递一个承诺数组,then
接受一个函数,该函数被传递一个具有所有原始承诺分辨率的数组。
回答by Henrique Barcelos
I'm not used to angular promise library, but the idea is as follows:
我不习惯 angular promise 库,但想法如下:
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);
});