這篇文章,我們一起探索一下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實作 ,會非常容易的從你的程式碼中分離出非同步任務。 這樣的話,你可以很容易的從你的應用程式中分離邏輯。

好看又实用的Bootstrap电商源码模板可以提高建站效率,下面本文给大家分享7款实用响应式Bootstrap电商源码,均可免费下载,欢迎大家使用!更多电商源码模板,请关注php中文网电商源码栏目!

Vue是一款流行的前端框架,在开发应用时经常会遇到各种各样的错误和问题。其中,Uncaught(inpromise)TypeError是常见的一种错误类型。在本篇文章中,我们将探讨它的产生原因和解决方法。什么是Uncaught(inpromise)TypeError?Uncaught(inpromise)TypeError错误通常出现在

在日常生活中,我们常常会遇到承诺与兑现之间的问题。无论是在个人关系中,还是在商业交易中,承诺的兑现都是建立信任的关键。然而,承诺的利与弊也常常会引起争议。本文将探讨承诺的利与弊,并给出一些建议,如何做到言出必行。承诺的利是显而易见的。首先,承诺可以建立信任。当一个人信守承诺时,他会让别人相信自己是一个可信赖的人。信任是人与人之间建立起的纽带,它可以让人们更加

本篇文章我们来了解 Vue2.X 响应式原理,然后我们来实现一个 vue 响应式原理(写的内容简单)实现步骤和注释写的很清晰,大家有兴趣可以耐心观看,希望对大家有所帮助!

Promise.resolve()详解,需要具体代码示例Promise是JavaScript中一种用于处理异步操作的机制。在实际开发中,经常需要处理一些需要按顺序执行的异步任务,而Promise.resolve()方法就是用来返回一个已经Fulfilled状态的Promise对象。Promise.resolve()是Promise类的一个静态方法,它接受一个

利用Promise对象,把普通函数改成返回Promise的形式,解决回调地狱的问题。明白Promise的成功失败调用逻辑,可以灵活的进行调整。理解核心知识,先用起来,慢慢整合吸收知识。

promise对象状态有:1、pending:初始状态,既不是成功,也不是失败状态;2、fulfilled:意味着操作成功完成;3、rejected:意味着操作失败。一个Promise对象一旦完成,就会从pending状态变为fulfilled或rejected状态,且不能再改变。Promise对象在JavaScript中被广泛使用,以处理如AJAX请求、定时操作等异步操作。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Dreamweaver Mac版
視覺化網頁開發工具

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),