【问题标题】:How do make jquery .each loop wait for response?如何让 jquery .each 循环等待响应?
【发布时间】:2015-12-10 19:01:32
【问题描述】:

当我调用第二个调用 AWS 中的脚本并等待 AWS 响应的函数时,如何在 .each 循环中等待迭代?
这是我的 .each 循环:

$('.subscriptionStatus').each(function(i, obj) {
    var sku = $(this).attr('data-sku');
    subscriptionStatus(sku, function(response) {
        var messageDiv = $(this).closest('.subscriptionMessage');

        var innerHtml = '';
        if (response){
            innerHtml = 'Successful';
        }else{
            innerHtml = 'Failed';
        }
        messageDiv.html(innerHtml);
    }//wait until 
}

对于每次迭代我调用一个函数,在里面我调用 AWS Lambda 中的一个脚本并且需要等待它的响应然后继续迭代:

function subscriptionStatus( sku, callback ){
    var lambda = new AWS.Lambda();
    lambda.invoke({
        FunctionName: 'MyFunction',
        Payload: JSON.stringify({
            "sku":sku
        })
    }, function(err, data){
        //response from AWS Lambda

        var success = data.Payload;
        if( success == 'true'){
            //NEED TO PASS TRUE BACK TO THE CURRENT ITERATION OF THE EACH LOOP
            callback(true); //correct way?
        }else{
            //NEED TO PASS FALSE BACK TO THE CURRENT ITERATION OF THE EACH LOOP
            callback(false); //correct way?
        }
    });
}

我的问题是迭代没有等待。
我的代码有什么问题?

【问题讨论】:

  • 您必须停止使用 .each,因为它永远不会等待异步操作。
  • 我并不是说这是居高临下之类的,但您应该完全阅读这篇文章:journal.stuffwithstuff.com/2015/02/01/… 这是对您在这里遇到的问题的超级有趣的描述。问题基本上是您在同步循环内调用异步函数。所以唯一的方法是阻塞循环中的每个调用,直到它返回。看起来 lambda 函数对同步执行有了新的支持,但是文档很模糊:docs.aws.amazon.com/lambda/latest/dg/…
  • @Milimetric 你说“所以唯一的方法是阻止循环中的每个调用,直到它返回。”我该怎么做?
  • @Miss_poker 你不能...除非 lambda 有同步选项。但请注意,该选项会导致您的应用程序在循环期间冻结,包括所有 css 动画、gif、加载栏和用户交互。
  • @KevinB 所以除了 .each 还有什么我可以使用的吗?

标签: jquery callback aws-lambda


【解决方案1】:

最简单的方法是使用 Promises 和 Deferreds(在 jQuery 中)

你的代码大概是什么:

function subscriptionStatus( sku ){
    var $dfd = jQuery.Deferred();
    var lambda = new AWS.Lambda();
    lambda.invoke({
        FunctionName: 'MyFunction',
        Payload: JSON.stringify({
            "sku":sku
        })
    }, function(err, data){
        if( data.Payload == 'true'){
             $dfd.resolve();
        }else{
            $dfd.reject();
        }
    });
    return $dfd.promise();
}

你现在可以这样做了:

subscriptionStatus(<sku>)
    .done(function() {

    }).fail(function() {

    });

现在来看花哨的部分:如何在 .each 循环中实现这一点?这取决于它是否需要按正确的顺序排列,或者您是否只需要等到它们全部完成。如果您只需要等待所有这些都以不特定的顺序完成:

// no particular order
var deferreds = []; // does nothing yet
$('.bla').each(function(){
    var $this = $(this);
    var $msgDiv = $this.closest('.subscriptionMessage');
    var sku = $this.attr('data-sku');
    var $dfd = subscriptionStatus(sku)
       .done(function() { $msgDiv.html('Successful'); })
       .fail(function() { $msgDiv.html('Failed'); });
    deferreds.push($dfd);
});
jQuery.when.apply(jQuery,deferreds)
    .done(function() { alert('all successful'); })
    .fail(function() { alert('any of the requests was not succesful'); })
    .always(function() { alert('they are all done'); });

【讨论】:

    【解决方案2】:

    你有没有让这个工作?我发现您的代码存在另一个与 Lambda 无关的问题。在您传递给订阅状态的回调中this 的值不会是.subscriptionStatus 元素。所以很可能messageDiv 总是一个空的jQuery 对象。您可以将其注销以进行验证。

    要修复它,请在 .each() 中保存对 this 的引用,如下所示:

    $('.subscriptionStatus').each(function(i, obj) {
      var _this = $(this); // save reference
      var sku = _this.attr('data-sku');
      subscriptionStatus(sku, function(response) {
        // now _this has a reference to the actual jQuery object wrapping the .subscriptionStatus element
        var messageDiv = _this.closest('.subscriptionMessage');
    
        var innerHtml = '';
        if (response){
            innerHtml = 'Successful';
        }else{
            innerHtml = 'Failed';
        }
        messageDiv.html(innerHtml);
      }//wait until 
    }
    

    我怀疑这将解决您的问题,除非您真的想阻止直到每个响应返回(这会损害渲染时间)。如果是这样,您应该查看 Promises。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-21
      • 2019-07-18
      • 2014-12-24
      • 2010-12-17
      • 1970-01-01
      • 2011-02-19
      • 2015-04-19
      相关资源
      最近更新 更多