2015-10-08 45 views
0

我已经继承了一个应用程序,扫描页面查找数据属性并相应地修改dom,添加处理程序等。jQuery异步编程模式?

我被要求实现动态标记,从而发出ajax调用来获取json数据,然后使用Handlebars根据返回的数据呈现新的html。

我需要告诉主要的外部应用程序等到所有的json调用在查找数据属性之前都已经被解析。

我应该采取什么样的模式来做到这一点?

任何帮助将非常感激。

感谢, 斯科特

更新

outer.js - 扫描DOM找事情做。

inner.js - 发布0-9 ajax调用(取决于我所在的页面)。每个ajax调用都有一个.then()函数,它调用Handlebars函数来写入标记。

如果我只有一个ajax调用,我可以将inner.js作为延迟传回给outer.js。然后,在那个ajax的.then()函数中,我只是调用inner.js.resolve()。

但是,如果我为9个可能的inner.js中的每一个都做了这个操作,#1会在#1运行后,但在#2结束之前解决。

如何动态设置outer.js用于等待它们全部解决的延迟数?

这似乎并不可能后期绑定一个这样的数组:在inner.js的顶部

var application = jQuery.Deferred(); 
var arrayOfAsync = []; 
application.done(arrayOfAsync); 

然后,当jQuery选择是在网页上找到,我可以做一个

arrayOfAsync.push(localPromise); 

但这似乎没有工作......应该吗?这会假定Deferred()实际上只是保持在一个正常的数组上,它可能不是......

+2

这是很多令人困惑的输入。请问一个简短的简洁问题(如此处所述:[问]],并最好添加一些*最小*代码来演示您的结构。 – Amit

+0

许多方法来做到这一点...取决于用例一点。需要更多关于ajax的详细信息......它是在一个循环中还是只有几个已知的调用等 – charlietfl

+0

这取决于我所在的页面。我正在使用jQuery来搜索页面,看看是否有什么需要动态内容。每个找到的元素都独立于其他元素运行。 – Scott

回答

2

您应该在这种情况下使用promise。

比方说,你有你的车把模板

<script id="PostsTempl" type="text/x-handlebars-template"> 
    {{#each posts}} 
     <li class="item-handlebars">{{body}}</li> 
    {{/each}} 
</script> 

应装满了一系列从Web API/web服务获取职位。

您将编译模板使用前:

var myTemplate = Handlebars.compile($("#PostsTempl").html()); 

现在,我们需要一个函数,它会调用web API/web服务,并会fetche一些数据:

function fetchData() 
{ 
    var deferred = $.Deferred(); 

    $.ajax({ 
     type: 'GET', 
     dataType: 'json', 
     url: 'my/api/posts/1/20', 
     data: {}, 
     success: function (jsonData) { 
      if (jsonData) { 
       deferred.resolve(jsonData); 
      } else { 
       deferred.reject(''); 
      } 
     }, 
     error: function (req, status, error) { 
      var errorMessage = (error.message) ? error.message : error; 
      deferred.reject(errorMessage); 
     } 
    }); 

    return deferred.promise(); 

} 

我们将使用$.ajaxGET的数据。我们已经确定这里promise

var deferred = $.Deferred(); 

,当我们取回数据,这将解决:

success: function (jsonData) { 
    if (jsonData) { 
     deferred.resolve(jsonData); 
    } else { 
     deferred.reject(''); 
    } 
}, 

或者最终被拒绝,如果没有数据。

return deferred.promise();将返回我们的承诺。

现在,我们可以调用它解决了承诺,并反馈一些数据的功能:

fetchData() 
    .then(function(data){ 
     // console.log(data); 
     var posts = {posts: data}; 
     $("#posts").append(myTemplate(posts)); 
     return true; 
    }) 
    .then(function(result){ 
     goLookForDataAttributes(); 
    }) 
    .fail(function (reason) { 
     if (reason !== '') { 
      alert('Something went wrong:' + reason); 
     } 
    }); 

当我们取回数据,我们追加的项目,以我们的模板:

.then(function(data){ 
    // console.log(data); 
    var posts = {posts: data}; 
    $("#posts").append(myTemplate(posts)); 
    return true; 
}) 

当一切完成我们称另一个功能在另一个.then()分支:

.then(function(result){ 
     goLookForDataAttributes(); 
    }) 

承诺可以被链接。 第二个.then()在第一个执行后被调用。

这是你需要的最后一位:

function goLookForDataAttributes() 
{ 
    $('#posts li.item-handlebars').each(function (index, item) { 
     $(item).addClass('big-font'); 
    }); 
} 

fiddle可能会帮助你。

在这个例子中,我解析帖子并添加一个类,当handlebards已呈现元素。

UPDATE:

既然你调用Web API/web服务,您可以并行执行的承诺,等到所有的Ajax请求已经完成并执行您的最后一个方法。

为了简单起见,我要创建一个假的承诺(这应该是你的Ajax请求):

function buildPromise(id) 
{ 
    var deferred = $.Deferred(); 

    setTimeout(function(){ 
     var data = {id: id, name: 'name: ' + id}; 
     deferred.resolve(data); 
    }, 1000); 

    return deferred.promise(); 
} 

,我会创建一个数组,比方说,10个许诺:

var promises = []; 

for (var p = 0; p < 10; p++) 
{ 
    promises.push(buildPromise(p)); 
} 

现在,我将能够并行运行所有这些承诺:

$.when.apply($, promises) 
    .then(function() { 
     for(var i = 0; i < arguments.length; i++) { 
      $('#content').append('<p>' + arguments[i].name + '</p>'); 
     } 
    }).then(function(results) { 
    return finalPromise(); 
}) 
.then(function(result){ 
    alert('success: ' + result.success); 
    alert('Finished'); 
}); 

$.when.apply($, promises) RESOLV将所有承诺一起并行,并在我们收回所有结果时返回。
结果可以在arguments中找到,并可以使用数组arguments[x]的索引读取。

当所有Ajax请求都被执行,我们将调用finalPromise

function finalPromise() 
{ 
    var deferred = $.Deferred(); 

    setTimeout(function(){ 
     var data = { success: true }; 
     deferred.resolve(data); 
    }, 1000); 

    return deferred.promise(); 

} 

finalPromise可能是一个普通的功能,没有承诺,也是如此。

This就是它的样子。

当然现在你必须适应你的情况。

+0

感谢您的彻底解答。然而,在我的场景中,我最多可以读取9个不同的json文件。所以,在你的模式中,我必须调用fetchData()最多9次。我只需要在0-9之后运行goLookForDataAttributes()ajax调用(和相关的handlebar机制)完成。 – Scott