如果您想等待 Promise 集合完成后再执行某些操作,我建议您使用 Promise.all
让生活更轻松
首先,我们将创建一个 loadImage 实用函数,该函数接受一个 url 并返回一个 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 是很好的第一步,因为它为我们提供了一种在程序中的任何位置使用 Promise 加载图像的通用方法。每次我们需要一张图片时,我们都不需要手动构造 Promise 来处理加载。只需致电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 Deferred
如果您正在寻找的话,这很容易转换为 jQuery 的 Deferred – bold
的变化
// loadImage :: String -> Promise<HTMLImageElement>
const loadImage = url => {
let d = $.Deferred()
var img = new Image()
img.src = url
img.onload = () => d.resolve(img)
img.onerror = (err) => d.reject(err)
return d.promise()
}
// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]>
const loadImagesForElement = (target, imageUrls) => {
return $.when(...imageUrls.map(loadImage)).then(
(...images) => images.forEach(i => target.appendChild(i)),
err => console.error(err)
)
}
如果你不能依赖扩展语法,事情就会变得有点难看——bold
的变化
// loadImagesForElement :: (HTMLElement, [String]) -> Promise<[HTMLImageElement]>
const loadImagesForElement = (target, imageUrls) => {
return $.when.apply($, imageUrls.map(loadImage)).then(
function(/* images */) {
Array.prototype.forEach.call(arguments, i => target.appendChild(i))
},
err => console.error(err)
)
}