一、前言
為了讓前端們從回呼的地獄中回到天堂, jQuery 也引入了 Promise 的概念。 Promise 是一種令程式碼異步行為更優雅的抽象,有了它,我們就可以像寫同步程式碼一樣去寫非同步程式碼。 jQuery 從1.5版本開始實現了 CommonJS Promise/A 規範這個重量級方案,不過沒有嚴格按照規範進行實現,有一些API上的差異。
好,讓我們來看看他們的特性吧( 本文範例基於jquery 1.8版本以上 )。
二、範例
以前寫動畫時,我們通常是這麼幹的:
$('.animateEle').animate({ opacity:'.5' }, 4000,function(){ $('.animateEle2').animate({ width:'100px' },2000,function(){ // 这样太伤了 $('.animateEle3').animate({ height:'0' },2000); }); });
假如這麼使用回調的話,那就太傷了。幸好,還有一些現成的 Promise 解決方案來優雅地解決這種問題。
我們來看看 jQuery 提供的解決方法。
var animate1 = function() { return $('.animateEle1').animate({opacity:'.5'},4000).promise(); }; var animate2 = function() { return $('.animateEle2').animate({width:'100px'},2000).promise(); }; var animate3 = function(){ return $('.animateEle3').animate({height:'0'},2000).promise(); }; // so easy,有木有,so clear,有木有 $.when(animate1()).then(animate2).then(animate3);
很明顯,更改後的程式碼更易懂易讀了。
但是,上面的程式碼,有些細節的東西並沒有透露,一不小心,就容易出錯,得不到我們想要的順序完成動畫的效果。以下讓我們來全面理解 jQuery 提供的 promise 和 deferred 物件的方法,看看到底如何使用。
三、promise和deffered物件方法
promise 物件其實就是 deferred 物件的特例,因為 promise 物件無法更改非同步狀態,而 deferred 物件可以。這點在他們的方法設計上,有著明顯的體現。
1.promise物件方法
通常,對於DOM,動畫,ajax相關方法,我們都可以使用 promise 方法。呼叫 promise 方法,傳回的是 promise 物件。可以鍊式呼叫 promise 方法。
promise物件常見的方法有三個 : done , fail , then 。
其它的方法就不要去記了, jquery 這裡的接口方法太多了,在我看來挺囉嗦的,就跟早期的事件方法綁定一樣, live , delegate , bind ,最終不是都歸為on 來管了麼。
程式碼範例,如下:
(1)DOM使用 promise 方法:
var box=$('#box'); box.promise().done(function(ele){ console.log(ele);//jQuery box });
(2)Ajax使用 promise 方法(預設回傳一個 promise 對象,所以可以不必明確呼叫 promise 方法):
$.post('/',{}).done(function(data){ console.log('请求成功'); }).fail(function(){ console.log('请求错误'); });
動畫範例已有,就不重複列出了。
2.deferred物件方法
那麼Deferred和Promise之間有什麼差別呢?如你在前面看到的,一個promise就是一個由非同步函數傳回的物件。當你想要自己寫一個這樣的函數時你需要使用一個deferred。
一個deferred物件能做的和一個promise物件差不多,但是它有兩個函數來觸發done()和fail()函數。
一個deferred物件擁有一個resolve()函數來處理一個成功的結果並執行與done()相關的函數。 reject()函數則用來處理失敗的結果並執行與fail()相關的函數。
你可以給resolve()和reject()函數都提供參數,然後它們都會傳遞給與done()和fail()相關的回呼函數。
promise物件沒有resolve()和reject()函數。這是因為你將promise放到了其他的腳本中並且你也不想promise去resolve或reject一個promise。
下面是一個關於deferred的簡單例子。 html只是一個簡單的擁有id屬性為”result”的空div。
$('#result').html('waiting...'); var promise = wait(); promise.done(result); function result() { $('#result').html('done'); } function wait() { var deferred = $.Deferred(); setTimeout(function() { deferred.resolve(); }, 2000); return deferred.promise(); }
其中,wait()函數傳回了一個promise。它將在2s之後被解析。除了setTimeout之外,非同步函數中所有的東西都能這樣使用,例如 動畫,Web worker等等。 wait()函數中的程式碼應該很清晰,我們使用了deferred對象,但是我們傳回了一個限制的promise物件。
對於 deferred 物件呢,也就是使用 $.Deferred() 方法,以及 $.when() 等方法創造出來的對象,有如下的常用方法:
resolve , reject , notify ; done , fail , progress ;
另外還有 promise 、 then 和 always 方法。
之所以這麼排版,是因為他們是對應的,也就是說: resolve 方法會觸發 done 的回調執行, reject 會觸發 fail 的回調, notify 會觸發 progress 的回調。
直接看程式碼:
var wait = function(ms) { var dtd = $.Deferred(); setTimeout(dtd.resolve, ms); // setTimeout(dtd.reject, ms); // setTimeout(dtd.notify, ms); return dtd.promise(); //此处也可以直接返回dtd }; wait(2500).done(function() { console.log('haha,师太,你可让老衲久等了'); }).fail(function() { console.log('失败了'); }).progress(function(res) { console.log('等待中...'); });
我们看到了,上面的代码中,在 wait 函数中,返回的是个 promise 对象,而不是 deferred 对象。
要知道, promise 对象是没有 resolve , reject , notify 等方法的,也就意味着,你无法针对 promise 对象进行状态更改,只能在 done 或 fail 中进行回调配置。所以,你如果这么调用 wait(2500).resolve() 将会报错,因为 wait(2500) 返回的是个 promise 对象,不存在 resolve 方法。
但是,这么做,有个好处,我们把 dtd 这个 deferred 对象放在了 wai t函数中,作为了局部变量,避免了全局的污染;进一步通过 promise 方法,转化 dtd 这个 deferred 对象为 promise 对象,避免了函数 wait 外部可能发生的状态更改(假如我们确实有这个需求)。
比如:
var wait = function(ms) { var dtd = $.Deferred(); setTimeout(dtd.resolve, ms); // setTimeout(dtd.reject, ms); // setTimeout(dtd.notify, ms); return dtd; //此处也可以直接返回dtd }; wait(2500).reject().fail(function(){ console.log('失败了...............'); });
我们在外部更改了 wait 返回的 deferred 对象的状态,这样必然触发该对象的 fail 回调函数。
对于 always 方法,从字面意思上就很容易理解, deferred 对象无论是 resolve 还是 reject ,都会触发该方法的回调。
3.其它共性
此处讲讲 then 和 $.when 方法的使用。它们对 promise 对象也适用。
$.when 方法接受多个 deferred 对象或者纯javascript对象,返回 promise 对象。
then 方法依次接受三个回调,分别为 deferred 对象 resolve , reject , notify 后触发的回调,返回一个 promise 对象。注意,必须传入函数,而该函数只有返回一个 promise 对象,才能够让异步事件按照预期顺序来执行。
我们来看看最开始的动画示例代码, $.when(animate1()).then(animate2).then(animate3) , $.when 方法中接受了一个 animate1 的函数执行结果,也就是得到了一个 promise 对象,而后的 then 中,则只是接受了一个变量名,这样得到的结果是一个匿名的函数体,而该函数中返回的是 promise 对象。正好符合了我们对 then 接受参数的要求。
假如我们把执行语句改成: $.when(animate1()).then(animate2()).then(animate3()) ,这样造成的结果就是三个动画同步执行了。与 $.when(animate1(),animate2(),animate3()) 无异。
既然 then 是如此要求,那么与 then 方法类似的 done , fail , progress 也是一样的。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

Python更适合数据科学和机器学习,JavaScript更适合前端和全栈开发。1.Python以简洁语法和丰富库生态著称,适用于数据分析和Web开发。2.JavaScript是前端开发核心,Node.js支持服务器端编程,适用于全栈开发。


熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

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

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

SublimeText3 Linux新版
SublimeText3 Linux最新版

WebStorm Mac版
好用的JavaScript開發工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。