2015-10-08 97 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