加载所有图像时解决承诺
Resolve promise when all images are loaded
我使用以下代码预加载图像:
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();
我认为图像都正确加载,因为我可以看到 'Resolved' 日志。
后来有人指出,上面的代码并不能保证在 resolve promise 之前加载所有图像。其实只解决了第一个promise。
有人建议我改用 $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();
这有效,但我想了解:
- 每个函数发生了什么;
- 为什么我需要
$q.all
来确保在解决承诺之前加载所有图像。
relevant docs 有点神秘。
不习惯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);
});
看看这个 plunkr。
你的函数:
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;
});
}
这个想法与 Henrique 的回答非常相似,但是 onload 处理程序用于解决每个承诺,而 onerror 用于拒绝每个承诺。
回答您的问题:
1) 承诺工厂
$q(function(resolve,reject) { ... })
构造一个 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 传递了一个承诺数组,then
接受一个函数,该函数传递一个数组,其中包含所有原始承诺的决议。
我使用以下代码预加载图像:
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();
我认为图像都正确加载,因为我可以看到 'Resolved' 日志。
后来有人指出,上面的代码并不能保证在 resolve promise 之前加载所有图像。其实只解决了第一个promise。
有人建议我改用 $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();
这有效,但我想了解:
- 每个函数发生了什么;
- 为什么我需要
$q.all
来确保在解决承诺之前加载所有图像。
relevant docs 有点神秘。
不习惯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);
});
看看这个 plunkr。
你的函数:
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;
});
}
这个想法与 Henrique 的回答非常相似,但是 onload 处理程序用于解决每个承诺,而 onerror 用于拒绝每个承诺。
回答您的问题:
1) 承诺工厂
$q(function(resolve,reject) { ... })
构造一个 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 传递了一个承诺数组,then
接受一个函数,该函数传递一个数组,其中包含所有原始承诺的决议。