2015-05-30 39 views
1

能anyoune請澄清什麼是錯用下面的代碼(也讀了不少文檔和例子,但仍然有不知道發生了什麼事)意外的延遲對象的行爲

function t() { 
    var d = $.Deferred(); 
    setTimeout(function(){ 
     d.resolve(); 
    }, 5000); 
    return d.promise(); 
} 
function test() { 
    var dd = $.Deferred(); 
    $.ajax("/echo/json/").done(function() { 
     dd = t(); 
     dd.done(function() { alert(" dd.done inside ajax")}); 
    }); 
    dd.done(function() { alert(" dd.done outside ajax")}); 
} 
test(); 

產量爲(以〜5 s):

"dd.done inside ajax:" 

爲什麼第二個.done不起作用?

+0

你盛開了開發者控制檯,以檢查是否存在錯誤? – Pointy

+0

沒有錯誤,但奇怪的是,第一個console.log(替換alert和url在瀏覽器中運行)輸出已經翻了一番。 W.T.H.? –

回答

0

您的第二個警報永遠不會被調用,因爲您原來的延遲分配給變量dd永遠不會被調用,因此它的.done()處理程序永遠不會被調用。

您創建一個延遲,並將其分配給dd這裏:

var dd = $.Deferred(); 

而且,當時您設置.done()處理這個:

dd.done(function() { alert(" dd.done outside ajax")}); 

但是,當你的Ajax功能完成後,您分配一個不同的承諾,用這一行dd變量:

dd = t(); 

因此,沒有任何東西能夠解決原來的承諾,所以它的.done()處理程序永遠不會被調用。


我建議這樣的設計來代替:

function t() { 
    var d = $.Deferred(); 
    setTimeout(function(){ 
     d.resolve(); 
    }, 5000); 
    return d.promise(); 
} 
function test() { 
    return $.ajax("/echo/json/").then(function() { 
     console.log("ajax call done"); 
     return t(); 
    }).then(function() { 
     console.log("after timer"); 
    }); 
} 

test().then(function() { 
    console.log("everything done"); 
}); 

工作演示:http://jsfiddle.net/jfriend00/atafc5hj/

這說明了以下概念這些都是瞭解的:

  1. 使用承諾已從$.ajax()返回,而不是創建自己的。
  2. 鏈接另一個承諾的活動。
  3. .then()處理程序返回另一個承諾,以使序列也等待該承諾。
  4. 從主函數返回鏈接的承諾,以便您可以看到什麼時候完成所有事情。

+0

太好了,現在我清楚地看到了一些事情,特別感謝建議的解決方案,這有助於理解一個主題,並且避免了我週末的頭痛 –

+0

但是...)仍然有一件事對我來說似乎不清楚。我注意到你使用.then()來分配回調而不是.done()。 我運行你的代碼(完美工作,再次感謝),除了使用.done而不是.dhen這裏︰drrrrrrrrrrrrrrrrrrrrrrrrrr: **返回$ .ajax(「/ echo/json /」)導致立即執行第二次回調(「定時器之後」),就好像它被分配給已經解析的延遲對象一樣。 –

+0

我使用.then(),因爲它是promise的標準處事方式,而不是jQuery的發明 – jfriend00

1

因爲該延遲對象未解析。您正在創建2個延遲對象並解析其中的一個。

2

讓我們來看看test()

function test() { 
    var dd = $.Deferred(); 
    $.ajax("/echo/json/").done(function() { 
     dd = t(); 
     dd.done(function() { alert(" dd.done inside ajax")}); 
    }); 
    dd.done(function() { alert(" dd.done outside ajax")}); 
} 
test(); 

局部變量dd被初始化到一個新的jQuery Deferred對象。然後,開始ajax操作,並給出一個「完成」回調,它將調用其他測試功能t()

$.ajax()調用將在其.done()回調運行很久之前立即返回。在此之後,爲函數開頭創建的Deferred實例建立另一個.done()回調。

現在,當阿賈克斯「完成」回調運行的dd —最初創建的Deferred對象—值將是覆蓋與無極從t()返回。最終.done()回調將會運行,但是沒有任何東西可以解決第一個Deferred實例,所以「外部」回調不會發生。

+0

謝謝。我看到我的錯在哪裏 –