【问题标题】:Using Deferred when all products have loaded加载所有产品后使用 Deferred
【发布时间】:2015-08-29 07:38:02
【问题描述】:

我有一个带有轮播的页面,每次幻灯片更改时都会发送一个 ajax 请求,并将与幻灯片相关的产品生成到底部的另一个轮播中。

在每张幻灯片更改的那一刻,使用 Ajax 成功绘制了产品,但我需要在加载 ajax 请求后使用产品启动滑块。现在滑块尝试在请求完成之前进行初始化。

在我添加的代码的底部,每个函数将每个 getProducts 函数添加到一个数组中,然后当它完成时,它应该初始化滑块。虽然在控制台中,消息“this is initialized”发生在 Ajax 请求中的“成功”消息之前。

我是否在这个例子中使用了延迟错误导致了这个问题?

        var products = [],
        uniqueProducts = [], 
        defs = [];           
        var el;
        $('.your-class [data-slick-index="' + currentSlide + '"] a').each(function(i) { 
              el = $(this).attr("href");      
              products.push(el);
              $.each(products, function(j, el) {
                  if ($.inArray(el, uniqueProducts) === -1)
                      uniqueProducts.push(el);
                      console.log("pushed" + uniqueProducts);
              });
        });
        function getProducts(el) {
          var def = new $.Deferred(); 
          var url = el;

          $.get(url, function(data) {  
                var imageArray = data.match(/<img itemprop="image" [\S\s]*?>/ig);
                var $image = $(imageArray[0]);
                var imageUrl = $image.attr('src');
                var name = $image.attr('title');
                var priceArray = data.match(/<p class="price">[\S\s]*?<\/p>/ig);
                var priceEl = $(priceArray[0]).find('[itemprop=price]');
                priceEl.children().remove();
                var price = priceEl.text() ? '$' + priceEl.text() : '';
                $( ".carousel2" ).append( '<div><img src=\" '+ imageUrl +'\"></div>');
                console.log("success");
                def.resolve();
          });
          return def.promise();
        }

      $.each(uniqueProducts, function(i, el) {
          defs.push(getProducts(el));
      });

      $.when($,defs).done(function () {
          $('.carousel2').slick({ speed: 500, autoplay: false, autoplaySpeed: 4000, arrows:false });
          console.log("this is initialized");
      });           
    } 

【问题讨论】:

  • 需要在最后一个函数$.when.apply($,defs).done(function () { $('.carousel2').slick( { speed: 500, autoplay: false, autoplaySpeed: 4000, arrows:false }); console.log("this is initialized"); });

标签: javascript jquery ajax jquery-deferred


【解决方案1】:

感谢this answer,构建uniqueProducts 将简化为两个单行代码。

var uniqueProducts = $('.your-class [data-slick-index="' + currentSlide + '"] a').map(function(el) {
    return $(el).attr('href');
}).get().filter(function(href, pos, self) {
    return self.indexOf(href) == pos;
});

getProducts() 应该简化如下:

function getProducts(url) {
    return $.get(url).then(function(data) {
        var image = $(data.match(/<img itemprop="image" [\S\s]*?>/ig)[0]);
        var price = $(data.match(/<p class="price">[\S\s]*?<\/p>/ig)[0]).find('[itemprop=price]').children().remove().end().text();
        return {
            name: image.attr('title'),
            image: image,
            price: price ? '$' + price : ''
        };
    });
}

请注意,getProducts() 现在没有副作用,而是返回一个数据对象。

然后通过使用uniqueProducts.reduce(...),您可以调用getProducts()处理promise传递的数据。

假设一切都发生在一个函数中,你最终会得到这样的结果:

function initializeCarousel() {
    return $('.your-class [data-slick-index="' + currentSlide + '"] a')
    .map(function(el) {
        return el.href;
    })
    .get()
    .filter(function(href, pos, self) {
        return self.indexOf(href) == pos;
    })
    .reduce(function(sequence, url) {
        var productPromise = getProducts(url);
        return sequence
        .then(function() {
            return productPromise;
        })
        .then(function(dataObj) {
            $(".carousel2").append(dataObj.image);
            // ... dataObj.name ...
            // ... dataObj.price ...
        }, function() {
            return sequence;//skip over error
        });
    }, $.when())//resolved starter promise for the reduction
    .then(function () {
        $('.carousel2').slick({ speed: 500, autoplay: false, autoplaySpeed: 4000, arrows:false });
        console.log("this is initialized");
    });
}

这种特殊的 .reduce 模式的特点是:

  • ajax 调用是并行进行的
  • 如果需要,可以非常简单地转换串行调用。
  • 附加到轮播的图像顺序将与缩减后的数组一致,即“正确顺序”。
  • 任何单个 ajax 错误都不会破坏整个企业。
  • 不需要中间的promises 数组或jQuery 的繁琐$.when.apply(null, promises)(或者其他库中更友好的.all())。

【讨论】:

    【解决方案2】:

    我已经有一段时间没有使用 $.when 了,但我认为您无需创建 $.Deferred() 实例就可以让它工作,因为 $.get 会为您返回这个。

    可能尝试让getProducts 返回$.get 而不是def.promise 并删除对def 的任何引用?

    希望能帮到你!

    p.s 我找到了一些旧代码,我在其中使用了这个 $.when,看看我是如何将它与 $.get 一起使用的。我已经对其进行了简化,以下内容应该可以工作。

    $.when([
      $.get("data/a.json"),
      $.get("data/b.json"),
      $.get("data/c.json")
    ]).done(function (t1, t2, t3) {
      app.a = t1[0];
      app.b = t2[0];
      app.c = t3[0];
    });
    

    【讨论】:

    • 感谢您的帮助,看起来我在最后一个函数中的 $.when 之后缺少一个“.apply”。如果可以,我会尝试您的解决方案,看看是否有效太
    • 没问题 :) 很高兴帮助我找到了一个我以前使用过的示例,并将其附加到我的答案中。您可以只传入一组$.get 请求,看起来应该可以正常工作。
    猜你喜欢
    • 2019-12-26
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 2013-02-12
    • 2019-02-10
    • 1970-01-01
    • 2016-03-16
    相关资源
    最近更新 更多