一旦所有的诺言都得到解决,我就尝试执行成功函数。但是成功函数在诺言得到解决之前就执行了。总结我的代码出了什么问题。

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);

}

最佳答案

如果您想在执行某些操作之前等待Promises的收集完成,我建议Promise.all



让生活轻松

首先,我们将创建一个loadImage实用程序函数,该函数带有url并返回PromiseHTMLImageElement

在这里,我们只需使用新的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加载图像。每次我们需要图像时,我们都不需要手动构造promise来处理加载。只需致电loadImage(someUrl),现在您就可以使用承诺的图像。

注意,我们现在甚至不需要显式循环。我们可以使用其他内置循环机制,例如mapforEach,一切都按预期工作。通过编写这样的小实用程序函数,我们最终将编写更少的代码。

警告:如果其中任何一个无法正确加载,将不会显示任何图像。



实际使用

大概是,您想以某种方式将图像添加到文档中,所以可能是这样的,而不是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 –粗体更改

// 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)
  )
}


如果您不能依赖于扩展语法,那么事情就会变得有些丑陋-以粗体显示

// 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)
  )
}

09-25 18:14