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