javascript - Promise 数组执行不正确

标签 javascript promise jquery-deferred

我试图在所有 promise 都得到解决后执行成功函数。但是成功函数是在 promise 得到解决之前执行的。找出我的代码中有什么问题。

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 并返回 HTMLImageElementPromise

从那里,我们只需使用新的 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),现在您就可以使用您 promise 的图像了。

注意,我们现在甚至不需要显式循环。我们可以使用其他内置循环机制,例如 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 延迟

如果您正在寻找的话,这很容易转化为 jQuery 的 Deferred – 粗体的变化

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

如果你不能依赖扩展语法,事情会变得有点难看 - 粗体的变化

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

关于javascript - Promise 数组执行不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43055339/

相关文章:

javascript - 为什么我需要在 Promise.then() 中关闭?

javascript - jQuery Deferred - 捕获与失败

javascript - 如何调用 URL、将其返回的 JSON 传递给函数并循环结果以记录名称

javascript - 忽略反斜杠后的字符 "\"- javascript

javascript - jQuery Loudev 多重选择不起作用

javascript - 使用 Ionic 框架将 ionic 按钮居中

javascript - 如何使用nodeJS和Puppeteer解决 "Target closed"错误?

node.js - 检查 Firebase 用户是否存在而不抛出错误

Javascript - 错误处理 - Promise 数组

jquery - 返回已解决的 promise