摘要:方法是的別名,用于指定發生錯誤時的回調函數。由于字符串不屬于異步操作判斷方法是字符串對象不具有方法,返回實例的狀態從一生成就是,所以回調函數會立即執行。出錯了等同于出錯了出錯了上面的代碼生成一個對象的實例,狀態為,回調函數會立即執行。
引言 Promise 是異步編程的一種解決方案,比傳統的解決方案——回調和事件——更合理且強大。最近的項目要用到這個,就參照阮一峰老師的《ES6標準入門》這本書簡單學一下了。
1 Promise 的含義所謂 Promise ,簡單來說就是一個容器,里面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上來看,Promise 是一個對象,從它可以獲取異步操作的消息。Promise 提供統一的 API,各種異步操作都可以用同樣的方法進行處理。
Promise 對象有以下兩個特點。
對象的狀態不受外界影響。
一旦狀態改變就不會再變。
2 基本用法ES6 規定,Promise 對象是一個構造函數,用來生成 Promise 實例。
舉個例子。
var promise = new Promise(function (resolve, reject) { // some code if (/* 異步操作成功*/) { resolve(value); } else { // 異步操作失敗 reject(error); } });
Promise 構造函數接收一個函數作為參數,該函數的兩個參數分別是 resolve 和 reject。他們是兩個函數,由 Javascript 引擎提供,不用自己部署。
resolve 函數的作用是將 Promise 對象的狀態從『未完成』(Pending)變為『成功』(Resolved),在異步操作成功的時候調用,并將異步操作的結果作為參數傳遞過去。 reject 函數的作用是,將 Promise 對象的狀態從『未完成』(Pending)變為『失敗』(Rejected)
當我們生成了一個 Promise 實例之后。就可以用 then 方法分別指定 Resolved 狀態和 Rejected 狀態的回調函數。
promise.then(function (value) { // success console.log(value); }, function (error) { // failed console.log(error); });
then 方法可以接受兩個回調函數作為參數。第一個回調函數是 Promise 對象的狀態變為 Resolved 時調用,第二個回調函數是 Promise 對象的狀態變為 Rejected 時調用。其中第二個參數是可選的,不一定要提供。這兩個函數都接收 Promise 對象傳出的值作為參數。
我們來個小例子
let promise = new Promise(function(resolve,reject){ console.log("Promise"); let value = "value"; resolve(value); }); promise.then(function(value){ console.log(value); }); console.log("Hi"); // Promise // Hi // value
上面的代碼中,Promise 新建后會立即執行,所以首先輸出的是 Promise。然后,then 方法指定的回調函數將當前腳本所有同步任務執行完成后才會執行,所以 Resolved 最后輸出。
3 Promise.prototype.then()Promise 實例具有 then 方法,即 then 方法是定義在原型對象 Promise.prototype 上的。它的作用是為 Promise 實例添加改變狀態時的回調函數。前面說過,then 方法的第一個參數是 Resolved 狀態的回調函數,第二個參數(可選)是 Rejected 狀態的回調函數。
then 方法返回的是一個新的 Promise 實例(注意 不是原來的那個 Promise 實例)。因此可以采用鏈式寫法,即 then 方法后面再調用另一個 then 方法。
getJSON("/posts.json").then(function(json) { return json.post; }).then(function(post) { // ... });
上面的代碼使用 then 方法依次指定了兩個回調函數。第一個回調函數完成以后,將會返回結果作為參數,傳入第二個回調函數。
然后采用鏈式的 then 可以指定一組按順序調用的回調函數。這時,前一個回調函數有可能返回的還是一個 Promise 對象(即有異步操作),而后一個回調函數就會等待該 Promise 對象的狀態發生變化,再被調用。
4 Promise.prototype.catch()Promise.prototype.catch 方法是 .then(null, rejection) 的別名,用于指定發生錯誤時的回調函數。
getJSON("/posts.json").then(function(posts) { // ... }).catch(function(error) { // 處理 getJSON 和 前一個回調函數運行時發生的錯誤 console.log("發生錯誤!", error); });
上面的代碼中,getJSON 方法返回一個 Promise 對象,如果該對象狀態變為 Resolved,則會調用 then 方法指定的回調函數;如果異步操作拋出錯誤,狀態就會變成 Rejected,然后調用 catch 方法指定的回調函數處理這個錯誤。另外, then 方法指定的回調函數如果在運行中拋出錯誤,也會被 catch 方法捕獲。
p.then((val) => console.log("fulfilled:", val)) .catch((err) => console.log("rejected", err)); // 等同于 p.then((val) => console.log("fulfilled:", val)) .then(null, (err) => console.log("rejected:", err));
下面是一個例子。
const promise = new Promise(function(resolve, reject) { throw new Error("test"); }); promise.catch(function(error) { console.log(error); }); // Error: test
上面的代碼中,Promise 拋出一個錯誤就被 catch 方法指定的回調函數所捕獲。注意,上面的寫法和下面兩種寫法是等價的。
// 寫法一 const promise = new Promise(function(resolve, reject) { try { throw new Error("test"); } catch(e) { reject(e); } }); promise.catch(function(error) { console.log(error); }); // 寫法二 const promise = new Promise(function(resolve, reject) { reject(new Error("test")); }); promise.catch(function(error) { console.log(error); });
由上面可以看出, reject 方法的作用等同于拋出錯誤。
如果 Promise 狀態已經變成 Resolved,在拋出錯誤是無效的。
const promise = new Promise(function(resolve, reject) { resolve("ok"); // Promise 狀態已變成 已完成 throw new Error("test"); }); promise .then(function(value) { console.log(value) }) .catch(function(error) { console.log(error) }); // ok
注意 一般來說,不要在 then 方法中定義 Reject 狀態的回調函數(即 then 的第二個參數),而是使用 catch 方法。
// bad promise .then(function(data) { // success }, function(err) { // error }); // good promise .then(function(data) { //cb // success }) .catch(function(err) { // error });
上面代碼中,第二種寫法要好于第一種寫法,理由是第二種寫法可以捕獲前面 then 方法執行中的錯誤,也更接近同步的寫法(try/catch)。因此,建議總是使用 catch 方法,而不使用 then 方法的第二個參數。
5 Promise.all()Promise.all 方法是將多個 Promise 對象實例包裝成一個新的實例。
var p = Promise.all([p1, p2, p3]);
上面的代碼中,Promise.all() 方法接受一個數組作為參數,p1, p2, p3 都是 Promise 對象的實例。如果不是,就會先調用下面講到的 Promise.resolve 方法,將參數轉換為 Promise 實例,再進一步處理(Promise.all 方法的參數不一定是數組,但是必須具有 Iterator 接口,且每個返回成員都是 Promise 實例)。
p 的狀態由 p1, p2, p3 決定,分成兩種情況
只有 p1, p2, p3 的狀態都變成 FulFilled,p 的狀態才會變成 FulFilled,此時 p1, p2, p3 的返回值組成一個數組,傳遞給 p 的回調函數。
只要 p1,p2,p3 中有一個被 Rejected ,p 的狀態就直接變成 Rejected,此時第一個被 Rejected 的實例的返回值會傳遞給 p 的回調函數。
下面是一個具體例子。
var promises = [2,3,4,5].map(function(id){ console.log(id) }); Promise.all(promises).then(function(res){ console.log(res); resolve }).catch(function(error){ console.log(error); }); // 先執行所有 promise 實例的異步操作,然后吧操作的結果打包數組返回 // 2 3 4 5 [undefined,undefined,undefined,undefined]
上面的代碼中,Promise 是包含 6 個 Promise 實例的數組,只有這 6 個實例的狀態都變成 fulfilled,或者其中有 1 個變成 rejected,才會調用 Promise.all 方法后面的回調函數。
6 Promise.race()Promise.race 方法同樣是將多個 Promise 實例包裝成一個新的 Promise 實例。
var p = Promise.race([p1, p2, p])
上面的代碼中,只要 p1, p2, p3 中 有一個實例 率先改變狀態,p 的狀態就跟著改變。那個率先改變的 Promise 實例的返回值就傳遞給 p 的回調函數。
Promise.race 方法的參數與 Promise.all 方法一樣,如果不是 Promise 實例,就會先調用下面講到的 Promise.resolve 方法,將參數轉為 Promise 實例,再進一步處理。
下面是一個例子,如果指定時間內沒有獲得結果,就將 Promise 的狀態變成 Rejected,否則就變為 Resolved。
const p = Promise.race([ fetch("/resource-that-may-take-a-while"), new Promise(function (resolve, reject) { setTimeout(() => reject(new Error("request timeout")), 5000) }) ]); p .then(console.log) .catch(console.error);
上面代碼中,如果 5 秒之內 fetch 方法無法返回結果,變量 p 的狀態就會變為 rejected,從而觸發 catch 方法指定的回調函數。
7 Promise.resolve()有時需要將現有對象轉為 Promise 對象,Promise.resolve 方法就起到這個作用。
const jsPromise = Promise.resolve($.ajax("/whatever.json"));
上面代碼將 jQuery 生成的 deferred 對象,轉為一個新的 Promise 對象。
Promise.resolve 等價于下面的寫法。
Promise.resolve("foo") // 等價于 new Promise(resolve => resolve("foo"))
Promise.resolve方法的參數分成四種情況。
7.1 參數是一個 Promise 實例如果參數是一個 Promise 實例,那么 Promise.resolve 將不做任何修改,原封不動的返回這個實例。
7.2 參數是一個 thenable 對象thenable 對象是指具有 then 方法的對象,例如下面這個對象
let thenable = { then: function(resolve, reject) { resolve(42); } };
Promise.resolve 方法會將這個對象轉為 Promise 對象,任何執行 thenable 對象的 then 方法。
let thenable = { then: function(resolve, reject) { resolve(42); } }; let p1 = Promise.resolve(thenable); p1.then(function(value) { console.log(value); // 42 });
上面的代碼中, thenable 對象的 then 方法執行后,對象 p1 的狀態就變為 resolved,從而立即執行最后的 then 方法指定的回調函數。輸出 42。
7.3 參數不是具有 then 方法的對象,或根本就不是對象如果參數是一個原始值,或者是一個不具有 then 方法的對象,那么 Promise.resolved 方法返回一個新的 Promise 對象,狀態為 Resolved。
const p = Promise.resolve("Hello"); p.then(function (s){ console.log(s) }); // Hello
上面代碼生成一個新的 Promise 對象的實例 p。由于字符串 Hello 不屬于異步操作(判斷方法是字符串對象不具有 then 方法),返回 Promise 實例的狀態從一生成就是 resolved,所以回調函數會立即執行。Promise.resolve 方法的參數,會同時傳給回調函數。
7.4 不帶有任何參數Promise.resolved 方法允許在調用時不帶有參數,而直接返回一個 Resolved 狀態的 Promise 對象。
所以,如果你希望得到一個 Promise 對象,比較方便的方法就是直接調用 Promise.resolve 方法。
const p = Promise.resolve(); p.then(function () { // ... });
上面代碼中的 p 就是一個 Promise 對象。
需要注意的是,立即 resolve 的 Promise 對象實在本輪 『事件循環』(event loop)結束時,而不是在下一輪『事件循環』開始時。
setTimeout(function () { console.log("three"); }, 0); Promise.resolve().then(function () { console.log("two"); }); console.log("one"); // one // two // three
上面代碼中,setTimeout(fn, 0) 在下一輪『事件循環』開始時執行,Promise.resolve() 在本輪『事件循環』結束時執行,console.log("one") 則是立即執行,因此最先輸出。
8 Promise.reject()Promise.reject(resson) 方法也會返回一個新的 Promise 實例,狀態為 Rejected (這個就暫時想不懂怎么應用了)。
const p = Promise.reject("出錯了"); // 等同于 const p = new Promise((resolve, reject) => reject("出錯了")) p.then(null, function (s) { console.log(s) }); // 出錯了
上面的代碼生成一個 Promise 對象的實例 p,狀態為 Rejected,回調函數會立即執行。
總結以上就是關于 Promise 學習的內容,如有錯誤的地方就請在下面評論處,發表一下看法,當然也可以放一下關于進階學習 Promise 的文章,大家一起學習。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/99982.html
摘要:工作當中經常會用到,在此進行深入學習異步編程解決方案是異步編程的一種解決方案,比傳統的解決方案回調函數和事件更合理和更強大。所有源碼注釋見學習筆記 工作當中經常會用到Promise,在此進行深入學習 異步編程解決方案 Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最早提出和實現,ES6 將其寫進了語言標準,統一了用法,原生提供了...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:今天來學習下吧其實這在筆試上也是一個考點基本介紹對象是熟悉的名字吧工作組提出的規范原本只是社區提出的構想一些外部函數庫率先實現了該功能中將其寫入了語言標準目的為異步操作提供統一接口是啥它就是一個中一個對象起著代理作用充當異步操作與回調函 今天來學習下Promise吧,其實這在筆試上也是一個考點. 基本介紹 Promise對象是CommonJS(熟悉的名字吧- -)工作組提出的規范.Pr...
摘要:概述在之前,在中的異步編程都是采用回調函數和事件的方式,但是這種編程方式在處理復雜業務的情況下,很容易出現回調地獄,使得代碼很難被理解和維護。如果不設置回調函數,內部的錯誤不會反應到外部。 本文是基于對阮一峰的Promise文章的學習整理筆記,整理了文章的順序、增加了更多的例子,使其更好理解。 1. 概述 在Promise之前,在js中的異步編程都是采用回調函數和事件的方式,但是這種編...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。寫一個符合規范并可配合使用的寫一個符合規范并可配合使用的理解的工作原理采用回調函數來處理異步編程。 JavaScript怎么使用循環代替(異步)遞歸 問題描述 在開發過程中,遇到一個需求:在系統初始化時通過http獲取一個第三方服務器端的列表,第三方服務器提供了一個接口,可通過...
閱讀 2572·2021-09-23 11:21
閱讀 1882·2021-09-22 15:15
閱讀 970·2021-09-10 11:27
閱讀 3440·2019-08-30 15:54
閱讀 651·2019-08-30 15:52
閱讀 1335·2019-08-30 15:44
閱讀 2349·2019-08-29 15:06
閱讀 2972·2019-08-28 18:21