Promises 数组执行不正确
Promises Array executing incorrectly
我正在尝试在所有承诺都得到解决后执行成功函数。但是成功函数是在承诺得到解决之前执行的。请告诉我我的代码有什么问题。
var loadImg = function(imageUrls, success, failure) {
var promises = [];
for (var i = 0; i < imageUrls.length; i++) {
(function(url, promise) {
var img = new Image();
img.onload = function() {
promise.resolve();
};
img.onerror = function() {
promise.reject();
};
img.src = url;
}(imageUrls[i], promises[i] = $.Deferred()));
}
$.when.apply($, promises).done(success, failure);
}
如果您想在执行某些操作之前等待 Promise 集合完成,我建议 Promise.all
让生活更轻松
首先,我们将制作一个 loadImage
效用函数,它接受 url 和 returns 一个 HTMLImageElement
的 Promise
从那里,我们只是使用我们新的 loadImage
实用程序映射您的 url 字符串数组——这会产生一个 Promises 数组,这正是 Promise.all
所期望的.
// loadImage :: String -> Promise<HTMLImageElement>
const loadImage = url => {
return new Promise((resolve, reject) => {
var img = new Image()
img.src = url
img.onload = () => resolve(img)
img.onerror = (err) => reject(err)
})
}
const imageUrls = ['a.jpg', 'b.jpg', 'c.jpg', 'd.jpg']
Promise.all(imageUrls.map(loadImage)).then(
images => console.log(images), // [<img src='a.jpg'>, <img src='b.jpg'>, ...]
err => console.error(err)
)
loadImage
是伟大的第一步,因为它为我们提供了一种通用方法,可以在我们程序的任何时候使用 promises 加载图像。每次我们需要一个图像时,我们不需要手动构造承诺来处理加载。只需致电 loadImage(someUrl)
,现在您就可以使用承诺的图像了。
注意,我们现在甚至不需要显式循环。我们可以使用其他内置循环机制,如 map
或 forEach
,一切都按预期工作。通过像这样编写一些实用函数,我们最终编写的代码会少很多。
警告:如果其中任何一个无法正确加载,将不会显示任何图像。
实际使用
据推测,您希望以某种方式将图像附加到您的文档中,因此 console.log
可能像这样
// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]>
const loadImagesForElement = (target, imageUrls) => {
return Promise.all(imageUrls.map(loadImage)).then(
images => images.forEach(i => target.appendChild(i)),
err => console.error(err)
)
}
loadImagesForElement(document.body, ['a.jpg', 'b.jpg', 'c.jpg'])
// => Promise { ... }
使用jQuery延迟
这很容易转化为 jQuery 的 Deferred,如果这正是您要寻找的 – bold
中的变化
// loadImage :: String -> Promise<HTMLImageElement>
const loadImage = url => {
<b>let d = $.Deferred()</b>
var img = new Image()
img.src = url
img.onload = () => <b>d.</b>resolve(img)
img.onerror = (err) => <b>d.</b>reject(err)
<b>return d.promise()</b>
}
// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]>
const loadImagesForElement = (target, imageUrls) => {
return <b>$.when(...</b>imageUrls.map(loadImage)<b>)</b>.then(
<b>(...</b>images<b>)</b> => images.forEach(i => target.appendChild(i)),
err => console.error(err)
)
}
如果你不能依赖扩展语法,事情会变得更糟——bold
的变化
// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]>
const loadImagesForElement = (target, imageUrls) => {
return $.when<b>.apply($,</b> imageUrls.map(loadImage)).then(
<b>function(/* images */) {</b>
<b>Array.prototype.forEach.call(arguments,</b> i => target.appendChild(i))
<b>}</b>,
err => console.error(err)
)
}
我正在尝试在所有承诺都得到解决后执行成功函数。但是成功函数是在承诺得到解决之前执行的。请告诉我我的代码有什么问题。
var loadImg = function(imageUrls, success, failure) {
var promises = [];
for (var i = 0; i < imageUrls.length; i++) {
(function(url, promise) {
var img = new Image();
img.onload = function() {
promise.resolve();
};
img.onerror = function() {
promise.reject();
};
img.src = url;
}(imageUrls[i], promises[i] = $.Deferred()));
}
$.when.apply($, promises).done(success, failure);
}
如果您想在执行某些操作之前等待 Promise 集合完成,我建议 Promise.all
让生活更轻松
首先,我们将制作一个 loadImage
效用函数,它接受 url 和 returns 一个 HTMLImageElement
Promise
从那里,我们只是使用我们新的 loadImage
实用程序映射您的 url 字符串数组——这会产生一个 Promises 数组,这正是 Promise.all
所期望的.
// loadImage :: String -> Promise<HTMLImageElement>
const loadImage = url => {
return new Promise((resolve, reject) => {
var img = new Image()
img.src = url
img.onload = () => resolve(img)
img.onerror = (err) => reject(err)
})
}
const imageUrls = ['a.jpg', 'b.jpg', 'c.jpg', 'd.jpg']
Promise.all(imageUrls.map(loadImage)).then(
images => console.log(images), // [<img src='a.jpg'>, <img src='b.jpg'>, ...]
err => console.error(err)
)
loadImage
是伟大的第一步,因为它为我们提供了一种通用方法,可以在我们程序的任何时候使用 promises 加载图像。每次我们需要一个图像时,我们不需要手动构造承诺来处理加载。只需致电 loadImage(someUrl)
,现在您就可以使用承诺的图像了。
注意,我们现在甚至不需要显式循环。我们可以使用其他内置循环机制,如 map
或 forEach
,一切都按预期工作。通过像这样编写一些实用函数,我们最终编写的代码会少很多。
警告:如果其中任何一个无法正确加载,将不会显示任何图像。
实际使用
据推测,您希望以某种方式将图像附加到您的文档中,因此 console.log
可能像这样
// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]>
const loadImagesForElement = (target, imageUrls) => {
return Promise.all(imageUrls.map(loadImage)).then(
images => images.forEach(i => target.appendChild(i)),
err => console.error(err)
)
}
loadImagesForElement(document.body, ['a.jpg', 'b.jpg', 'c.jpg'])
// => Promise { ... }
使用jQuery延迟
这很容易转化为 jQuery 的 Deferred,如果这正是您要寻找的 – bold
中的变化// loadImage :: String -> Promise<HTMLImageElement>
const loadImage = url => {
<b>let d = $.Deferred()</b>
var img = new Image()
img.src = url
img.onload = () => <b>d.</b>resolve(img)
img.onerror = (err) => <b>d.</b>reject(err)
<b>return d.promise()</b>
}
// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]>
const loadImagesForElement = (target, imageUrls) => {
return <b>$.when(...</b>imageUrls.map(loadImage)<b>)</b>.then(
<b>(...</b>images<b>)</b> => images.forEach(i => target.appendChild(i)),
err => console.error(err)
)
}
如果你不能依赖扩展语法,事情会变得更糟——bold
的变化// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]>
const loadImagesForElement = (target, imageUrls) => {
return $.when<b>.apply($,</b> imageUrls.map(loadImage)).then(
<b>function(/* images */) {</b>
<b>Array.prototype.forEach.call(arguments,</b> i => target.appendChild(i))
<b>}</b>,
err => console.error(err)
)
}