2012-05-19 50 views
2

關於如何使用Jquery.deferred來使一個慢同步函數返回一個承諾,而不是一個簡短的問題。 什麼我迄今所做的是:語法爲Jquery.deferred,使同步函數返回承諾

function sayIt(ms) { 
    setTimeout(function() { console.log('what I say'); }, ms); 
} 

function doIt() { 
    return $.Deferred(function() { sayIt(2000); }).promise(); 
} 


doIt().then(function() { console.log('ah'); }); 

的sayIt(2000)總是經歷,但之後「然後」鏈接的功能永遠不會觸發。

如果我這樣做:

doIt().then(console.log('ah')); 

的「啊」來了馬上,然後「我說的」 2000毫秒後 - 我想知道的當然是相反的 - 即在兩秒鐘後我然後馬上得到'我說的'然後'啊'。

任何建議表示讚賞!

+0

'doIt方法(),然後(執行console.log( '啊'));'日誌立刻因爲這個執行' console.log',然後將其返回給'then'。 – Armatus

+0

@Armatus好的謝謝,這是有道理的,我知道第二個doIt()鏈的語法無論如何都是錯誤的。但是第一個doIt()鏈呢?爲什麼doIt()不返回sayIt(2000)返回時解決的承諾?提前致謝! – Petrov

+0

這不是同步的 - 使用'setTimeout'使它異步。 – Alnitak

回答

10

要做點什麼同步,但仍使用一個承諾,做:

function slowPromise() { 

    var def = $.Deferred(); 

    // do something slow and synchronous 
    ... 

    // resolve the deferred with the result of the slow process 
    def.resolve(res); 

    // and return the deferred 
    return def.promise(); 
} 

的效果是,你仍然可以得到一個承諾,但這一承諾已經得到解決,因此,這是它以後註冊任何.then()立即收益。

該模式的優點是,如果隨後用異步方式替換同步代碼,該函數仍具有相同的外部接口。

+1

這裏是你的解決方案jsfiddle:http://jsfiddle.net/petrov/nzDae/但它似乎仍然在做同樣的事情 - '結束'在'中間'之前... – Petrov

+0

我可以看到在jsfiddle高於def。resolve(result)立即發射一個尚未定義的'結果',因爲慢速函數尚未返回。問題是,說它完成時不會觸發事件 – Petrov

+0

@Petrov「慢」與「同步」不一樣。你必須在異步函數的末尾「解決」承諾_。 – Alnitak

3

如果你想在超時過期後執行的函數,你需要調用resolve()Deferred對象在超時到期函數中:

function sayIt(ms) { 
    var d = $.Deferred(); 
    setTimeout(function() { 
     console.log('what I say'); 
     d.resolve() 
    }, ms); 
    return d; 
} 

這樣,你約束Deferred的分辨率反對超時到期。

要實現什麼,我相信是你的意圖:

function doIt() { 
    return sayIt(2000).promise() 
} 

.promise()調用是可選的。它僅限制呼叫者的可用接口:通過返回Promise而不是原始的Deferred對象,呼叫者只能對事件作出反應,但不能觸發事件。參考:http://api.jquery.com/deferred.promise/

最終,原來的通話:

doIt().then(function() { console.log('ah'); }); 

將輸出:

// 2 seconds delay 
what I say 
ah