jQuery Deferred和Promise建立響應式應用程式詳細介紹_jquery
這篇文章,我們一起探索一下JavaScript 中的Deferred 和Promise 的概念,它們是JavaScript 工具包(如Dojo和MochiKit)中非常重要的一個功能,最近也首次亮相於流行的JavaScript 庫jQuery(已經是1.5版本的事情了)。 Deferred 提供了一個抽象的非阻塞的解決方案(如 Ajax 請求的回應),它會建立一個 「promise」 對象,其目的是在未來某個時間點回傳一個回應。如果您之前沒有接觸過 “promise”,我們將會在下面做詳細介紹。
抽象來說,deferreds 可以理解為表示需要長時間才能完成的耗時操作的一種方式,相比於阻塞式函數它們是異步的,而不是阻塞應用程序等待其完成然後返回結果。 deferred對 象會立即傳回,然後你可以把回呼函數綁定到deferred物件上,它們會在非同步處理完成後被呼叫。
Promise
你可能已經閱讀過一些關於promise和deferreds實作細節的資料。在本章節中,我們大致介紹下promise如何運作,這些在幾乎所有的支援deferreds的javascript框架中都是適用的。
一般情況下,promise作為一個模型,提供了一個在軟體工程中描述延時(或未來)概念的解決方案。它背後的思想我們已經介紹過:不是執行一個方法然後阻塞應用程式等待結果返回,而是返回一個promise物件來滿足未來值。
舉一個例子會有助於理解,假設你正在建立一個web應用程序, 它很大程度上依賴第三方api的數據。那麼就會面臨一個共同的問題:我們無法得知一個API回應的延遲時間,應用程式的其他部分可能會被阻塞,直到它返回 結果。 Deferreds 對這個問題提供了一個更好的解決方案,它是非阻塞的,並且與程式碼完全解耦 。
Promise/A提議'定義了一個'then‘方法來註冊回調,當處理函數傳回結果時回調會執行。它回傳一個promise的偽代碼看起來是這樣的:
promise.then(function( futureValue ) {
/* handle futureValue */
});
promise.then(function( futureValue ) {
/* do something else */
});
•resolved:在這種情況下,資料是可用
•rejected:在這種情況下,出現了錯誤,沒有可用的值
幸運的是,'then'方法接受兩個參數:一個用於promise得到了解決(resolved),另一個用於promise拒絕(rejected)。讓我們回到偽代碼:
程式碼如下:
promise. then( function( futureValue ) {
/* we got a value */
} , function() {
/* something went wrong */
程式碼如下:
when(
>promise2,
...
).then(function( futureValue1, futureValue2, ... ) {
/* all promises have completed and are resolved */
程式碼如下:
when( function()
/* animation 1 */
/* return promise 1 */
}, function(){
/* animation 2 */
/* return promise 2 */
} ).then(function(){
/* once both animations have completed we can then run our additional logic */
这意味着,基本上可以用非阻塞的逻辑方式编写代码并异步执行。 而不是直接将回调传递给函数,这可能会导致紧耦合的接口,通过promise模式可以很容易区分同步和异步的概念。
在下一节中,我们将着眼于jQuery实现的deferreds,你可能会发现它明显比现在所看到的promise模式要简单。
jQuery的Deferreds
jQuery在1.5版本中首次引入了deferreds。它 所实现的方法与我们之前描述的抽象的概念没有大的差别。原则上,你获得了在未来某个时候得到‘延时'返回值的能力。在此之前是无法单独使用的。 Deferreds 作为对ajax模块较大重写的一部分添加进来,它遵循了CommonJS的promise/ A设计。1.5和先前的版本包含deferred功能,可以使$.ajax() 接收调用完成及请求出错的回调,但却存在严重的耦合。开发人员通常会使用其他库或工具包来处理延迟任务。新版本的jQuery提供了一些增强的方式来管理 回调,提供更加灵活的方式建立回调,而不用关心原始的回调是否已经触发。 同时值得注意的是,jQuery的递延对象支持多个回调绑定多个任务,任务本身可以既可以是同步也可以是异步的。
您可以浏览下表中的递延功能,有助于了解哪些功能是你需要的:
jQuery.Deferred() | 创建一个新的Deferred对象的构造函数,可以带一个可选的函数参数,它会在构造完成后被调用。 |
jQuery.when() | 通过该方式来执行基于一个或多个表示异步任务的对象上的回调函数 |
jQuery.ajax() | 执行异步Ajax请求,返回实现了promise接口的jqXHR对象 |
deferred.then(resolveCallback,rejectCallback) | 添加处理程序被调用时,递延对象得到解决或者拒绝的回调。 |
deferred.done() |
当延迟成功时调用一个函数或者数组函数. |
deferred.fail() |
当延迟失败时调用一个函数或者数组函数.。 |
deferred.resolve(ARG1,ARG2,...) | 调用Deferred对象注册的‘done'回调函数并传递参数 |
deferred.resolveWith(context,args) | 调用Deferred对象注册的‘done'回调函数并传递参数和设置回调上下文 |
deferred.isResolved | 确定一个Deferred对象是否已经解决。 |
deferred.reject(arg1,arg2,...) | 调用Deferred对象注册的‘fail'回调函数并传递参数 |
deferred.rejectWith(context,args) | 调用Deferred对象注册的‘fail'回调函数并传递参数和设置回调上下文 |
deferred.promise() | 返回promise对象,这是一个伪造的deferred对象:它基于deferred并且不能改变状态所以可以被安全的传递 |
jQuery延遲實作的核心是jQuery.Deferred:一個可以鍊式呼叫的建構子。 …… 需要注意的是任何deferred物件的預設狀態是unresolved, 回呼會透過 .then() 或 .fail()方法加入到佇列,並在稍後的過程中執行。
以下這個$.when() 接受多個參數的範例
複製程式碼
複製程式碼
程式碼如下
function successFunc(){ console.log( “success!” ); }
function failureFunc(){ console.log( “failure!” ); }
$.ajax( "/main.php" ),
$.ajax( "/modules.php" ),
$.ajax( “/lists.php” )
) .then( successFunc, failureFunc );
複製程式碼
程式碼如下:
function getgets考慮$.get( “latestNews.php”, function(data){
console.log( “news data received” );
$( “.news” ).html(data);
} ) ;
}
function getLatestReactions() {
return $.get( “latestReactions.php”, function(data){
console.log( “reactions data received” );
console.log( “reactions data received” );
$ ( “.reactions” ).html(data);
} );
}
function prepareInterface() {
return $.Deferred(function( dfd ) {
var latest = $( “.news, .reactions” );
latest.slideDown( 500, dfd.resolve );
latest.addClass( “active” );
}).promise();
}
$.when(
).then(function(){
console.log(>).then(function(){
console.log( after requests succ 」 ); }).fail(function(){ console.log( “something went wrong!” );
});
複製程式碼
程式碼如下:
程式碼如下:快取機制需要確保腳本不管是否已經存在於緩存,只能被要求一次。 因此,為了快取系統可以正確地處理請求,我們最終需要寫出一些邏輯來追蹤綁定到給定url上的回調。
值得慶幸的是,這恰好是deferred所實現的那種邏輯,因此我們可以這樣來做:
複製代碼
程式碼如下:
程式碼相當簡單:我們為每一個url快取一個promise物件。 如果給定的url沒有promise,我們建立一個deferred,並發出請求。 如果它已經存在我們只需要為它綁定回呼。 該解決方案的一大優點是,它會透明地處理新的和快取過的請求。 另一個優點是基於deferred的快取 會優雅地處理失敗情況。 當promise以'rejected'狀態結束的話,我們可以提供一個錯誤回調來測試:
$.cachedGetScript( url ).then( successCallback, errorCallback );請求是否快取過,上面的程式碼段都會正常運作!
通用非同步快取
為了使程式碼盡可能的通用,我們建立一個快取工廠並抽像出實際需要執行的任務:
return function( key, callback ) {
if ( !cache[ key ] ) {
cache[ key ] = $.Deferred(function( defer ) {
requestFunction( defer, key ) ;
}).promise();
}
return cache[ key ].done( callback );
};
}
程式碼如下:
$.cachedGetScript = $.createCache(function( defer, url ) {
});
}); >
每次呼叫createCache將建立一個新的快取庫,並傳回一個新的快取檢索函數。現在,我們擁有了一個通用的快取工廠,它很容易實現涉及從快取中取值的邏輯場景。
複製程式碼
程式碼如下:
$.loadImage = $. createCache(function( defer, url ) {
var image = new Image();
function cleanUp() {
image.onload = image.onerror = null;
}
}
defer. then( cleanUp, cleanUp );
image.onload = function() {
defer.resolve( url );
};
image.src = url; >
程式碼如下:無論image.png是否已經被加載,或者正在加載過程中,快取都會正常工作。
快取資料的API回應
哪些你的頁面的生命週期過程中被認為是不可變的API請求,也是快取完美的候選場景。 例如,執行以下操作:
複製程式碼
程式碼如下:
});
程式程式碼>允許你在Twitter上進行搜索,同時緩存它們:
複製代碼
代碼如下:
定時
基於deferred的快取並不限定於網路請求;它也可以被用於定時目的。
例如,您可能需要在網頁上給定一段時間後執行一個動作,來吸引用戶對某個不容易引起注意的特定功能的關注或處理一個延時問題。 雖然setTimeout適合大多數用例,但在計時器出發後甚至理論上過期後就無法提供解決方案。 我們可以使用以下的快取系統來處理:
var ready ;
$(function() { readyTime = jQuery.now(); });
$.afterDOMReady = $.createCache(function( defer, delay ) {
delay = delay || 0 $(function() {
var delta = $.now() - readyTime;
if ( delta >= delay ) { defer.resolve(); }
else {
setTimeout( defer.resolve, delay - delta );
}
});
});
同步多個動畫 動畫是另一個常見的非同步任務範例。 然而在幾個不相關的動畫完成後執行程式碼仍然有點挑戰性。雖然在jQuery1.6中才提供了在動畫元素上取得promise物件的功能,但它是很容易的手動實作:
程式碼如下:
$.fn.animatePromise = function( prop, speed, easing, callback ) {
var elements = this;
return $.Deferred(function ( defer ) {
elements.animate( prop, speed, easing, function() {
defer.resolve();
if ( callback ) {
callback.apply( s, arguments );
}
});
}).promise();
程式碼如下:
var fadeDiv1 =
var fadeDiv1 = kvar( #div1" ).animatePromise({ opacity: 0 }),
fadeDiv2In = $( "#div1" ).animatePromise({ opacity: 1 }, "fast" );
$.when( fadeDiv1Out, fadeDiv2In ).done(function() {
/* both animations ended */
});
複製程式碼
程式碼如下:
$. slideDown", "slideUp", "slideToggle", "fadeIn", "fadeOut", "fadeToggle" ],
function( _, name ) {
$.fn[ name "Promise" ] = function( speed , easing, callback ) {
var elements = this;
return $.Deferred(function( defer ) {
elements[ name ]( speed, easing, function() {
defer.resolve( );
if ( callback ) {
callback.apply( this, arguments );
}
}).promise();
}
; });
複製代碼
程式碼如下:
$.when(
$( "#div2" ).fadeInPromise ( "fast" ) ).done(function() { /* both animations are done */
});
一次性事件
複製程式碼
程式碼如下:
var buttonClicked = false;
$( "#myButton" ).click(function() {
if ( !buttonClicked ) {
buttonClicked = true;
showPanel();
}
}); 複製程式碼 程式碼如下:
if ( buttonClicked ) { /* perform specific action */ }
這是一個非常耦合的解決方法。 如果你想添加一些其他的操作,你必須編輯綁定程式碼或拷貝一份。 如果你不這樣做,你唯一的選擇是測試buttonClicked。由於buttonClicked可能是false,新的程式碼可能永遠不會被執行,因此你 可能會失去這個新的動作。
使用deferreds我們可以做的更好(為簡化起見,下面的程式碼將只適用於一個單一的元素和一個單一的事件類型,但它可以很容易地擴展為多個事件類型的集合):
fn. function( event, callback ) {
var element = $( this[ 0 ] ),
defer = element.data( "bind_once_defer_" event );
if ( !defer ) {
defer = $.Deferred();
function deferCallback() {
element.unbind( event, deferCallback );
defer.resolveWith( this, arguments );
}
el.bind( , deferCallback )
element.data( "bind_once_defer_" event , defer );
}
return defer.done( callback ).promise();
}
•檢查該元素是否已經綁定了一個給定事件的deferred物件
•如果沒有,創建它,使它在觸發該事件的第一時間解決
•然後在deferred上綁定給定的回調並回傳promise
程式碼雖然很冗長,但它會簡化相關問題的處理。 讓我們先定義一個輔助方法:
程式碼如下:
程式碼如下:
return this.bindOnce( "click", callback );
複製程式碼
程式碼如下:
var openPanel = $( myButton" ).firstClick();
複製程式碼
程式碼如下:
程式碼如下:
Panle .done(function() { /* perform specific action */ });
如果面板沒有打開,行動將得到延遲到單擊該按鈕時。
假如,我們有一個按鈕,可以打開一個面板,請求其內容然後淡入內容。使用我們前面定義的助手方法,我們可以這樣做:
複製程式碼
程式碼如下:
程式碼如下:
程式碼如下:
panel.slideDownPromise ()
).done(function( ajaxResponse ) {
panel.html( ajaxResponse[ 0 ] ).fadeIn();
});
});
});




$( "#myButton" ).firstClick(function() {
var panel = $( "#myPanel" ),
promises = [];
$( "img" , panel ).each(function() {
var image = $( this ), src = element.attr( "data-src" );
if ( src ) {
promises.push(
$.loadImage( src ).then( function() {
image.attr( "src", src );
}, function() {
image.attr( "src", " error.png" );
} )
);
}
});
promises.push( panel.slideDownPromise() );
$ .when.apply( null, promises ).done(function() { panel.fadeIn(); });
});
這裡的訣竅是追蹤所有的LoadImage 的promise ,接下來加入面板slideDown動畫。 因此首次點擊按鈕時,面板將slideDown並且圖像將開始載入。 一旦完成向下滑動面板和已加載的所有圖像,面板才會淡入。
在特定延時後載入頁面上的圖片
假如,我們要在整個頁面實作遞延影像顯示。 要做到這一點,我們需要的HTML的格式如下:




意思非常簡單:
•image1.png,第三個影像立即顯示,一秒鐘後第一個影像顯示
•image2.png 一秒後顯示第二張影像,兩秒鐘後顯示第四個影像
我們將如何實現?
$( "img" ). function() {
var element = $( this ),
src = element.attr( "data-src" ),
after = element.attr( "data-after" );
if ( src ) {
$.when(
$.loadImage( src ),
$.afterDOMReady( after )
).then(function() {
element. src", src );
}, function() {
element.attr( "src", "error.png" );
} ).done(function() {
element. fadeIn();
});
}
});
如果我們想要延遲載入的圖片本身,程式碼會有所不同:
$( "img" ).each(function() {
var element = $( this ),
src = element.attr( "data-src" ),
after = element.attr( "data-after" );
if ( src ) {
$.afterDOMReady( after, function() {
$.loadImage( src ).then(function() {
element.attr( "src", src );
}, function() {
element.attr( "src", "error.png" );
} ).done(function() {
element.fadeIn();
});
} );
}
});
這裡,我們先在嘗試載入圖片之前等待延遲條件滿足。當你想要在頁面載入時限製網路請求的數量會非常有意義。
結論
正如你所看到的,即使在沒有Ajax請求的情況下,promise也非常有用的。透過使用jQuery 1.5中的deferred實作 ,會非常容易的從你的程式碼中分離出非同步任務。 這樣的話,你可以很容易的從你的應用程式中分離邏輯。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

隨著行動裝置的普及,網頁設計需要考慮到不同終端的裝置解析度和螢幕尺寸等因素,以實現良好的使用者體驗。在實現網站的響應式設計時,常常需要使用到圖片輪播效果,以展示多張圖片在有限的視覺視窗中的內容,同時也能夠增強網站的視覺效果。本文將介紹如何使用CSS實現響應式圖片自動輪播效果,並提供程式碼範例和解析。實現思路響應式圖片輪播的實現可以透過CSS的flex佈局來實現。在

在日常生活中,我們常常會遇到承諾與兌現之間的問題。無論是在個人關係中,或是在商業交易中,承諾的兌現都是建立信任的關鍵。然而,承諾的利與弊也常常會引起爭議。本文將探討承諾的利與弊,並給予一些建議,如何做到言出必行。承諾的利是顯而易見的。首先,承諾可以建立信任。當一個人信守承諾時,他會讓別人相信自己是個可信賴的人。信任是人與人之間建立的紐帶,它可以讓人們更加

如何使用HTML、CSS和jQuery製作一個響應式的標籤雲標籤雲是一種常見的網頁元素,用於展示各種關鍵字或標籤。它通常以不同的字體大小或顏色來展示關鍵字的重要性。在本文中,將介紹如何使用HTML、CSS和jQuery來製作一個響應式的標籤雲,並給出具體的程式碼範例。在建立HTML結構首先,我們需要在HTML中建立標籤雲的基本結構。可以使用一個無序列表來表示標籤

使用CSS實現響應式滑動選單的教程,需要具體程式碼範例在現代網頁設計中,響應式設計成為了一個必備的技能。為了適應不同的裝置和螢幕尺寸,我們需要為網站添加一個響應式選單。今天,我們將使用CSS來實作一個響應式的滑動選單,並為您提供具體的程式碼範例。首先,讓我們來看看實現效果。我們將建立一個導覽欄,當螢幕寬度小於一定閾值時,會自動折疊起來,並透過點擊選單按鈕展開。

如何使用HTML、CSS和jQuery製作一個響應式的音樂播放清單在現代社會中,音樂已經成為人們生活中不可或缺的一部分。為了方便使用者隨時隨地欣賞自己喜愛的音樂,製作一個響應式的音樂播放清單是非常必要的。在本文中,將介紹如何使用HTML、CSS和jQuery來製作一個具有響應式設計的音樂播放列表,並提供詳細的程式碼範例。步驟一:HTML結構設計首先,我們要設

Promise.resolve()詳解,需要具體程式碼範例Promise是JavaScript中一種用來處理非同步操作的機制。在實際開發中,常常需要處理一些需要依序執行的非同步任務,而Promise.resolve()方法就是用來傳回一個已經Fulfilled狀態的Promise物件。 Promise.resolve()是Promise類別的靜態方法,它接受一個

如何使用HTML和CSS建立一個響應式輪播圖佈局在現代的網頁設計中,輪播圖是一個常見的元素。它能夠吸引用戶的注意力,展示多個內容或圖片,並且能夠自動切換。在本文中,我們將介紹如何使用HTML和CSS建立一個響應式的輪播圖佈局。首先,我們需要建立一個基本的HTML結構,並且加入所需的CSS樣式。以下是一個簡單的HTML結構:<!DOCTYPEhtml&g

如何使用HTML、CSS和jQuery製作一個響應式的滾動通知欄隨著行動裝置的普及和使用者對網站存取體驗要求的提高,設計一個響應式的滾動通知欄變得越來越重要。響應式設計可確保網站在不同裝置上都能正常顯示,且使用者可以輕鬆查看通知內容。本文將介紹如何使用HTML、CSS和jQuery來製作一個響應式的滾動通知欄,並提供具體的程式碼範例。首先,我們需要建立HTM
