摘要:三種狀態進行中已完成,又稱已失敗。如果的狀態是,那么的回調函數就會等待的狀態改變,在此之前不會有結果。等價于例子例子的概念是實例的別名,用于指定發生錯誤時的回調函數。
『ES6知識點總結』變量的解構賦值
本文主要內容如下:
1 Promise是什么?
1.1 特點:
1.2 三種狀態:
1.3 用處:
1.4 Promise缺點:
1.5 歷史過程
2 生成promise實例
3 promise實例的then()方法
4 resolve函數的參數可以是另一個Promise實例
5 Promise的方法(多種)
5.1 Promise.all()
5.2 Promise.race()
5.3 Promise.reject(reason)
5.4 Promise.resolve(obj)
6 Promise.prototype.catch()的概念
6.1 盡量不定義then的reject方法
6.2 catch方法返回的還是一個Promise對象,因此后面還可以接著調用then方法。
7
7.1 如果前面的promise和then()沒有報錯,則會跳過catch方法。
7.2 拋錯的冒泡性質
7.2.1 如果Promise狀態已經變成resolved,再拋出錯誤是無效的。
7.2.2 Promise在下一輪“事件循環”再拋出錯誤
7.2.3 如果沒有處理錯誤的回調函數,就沒有反應
7.2.4 catch方法之中,還能再拋出錯誤。
8 node.js的unhandledRejection
9 done()
10 finally()
Promise是什么?
01、是一個對象,用來傳遞異步操作的消息。
02、代表了某個未來才會知道結果的事件(通常是一個異步操作)。
03、提供一個統一的API,可以進一步處理,控制異步操作。
特點:
01、對象的狀態不受外界影響。
02、代表一個異步操作。
三種狀態:
Pending(進行中) Resolved(已完成,又稱Fulfilled) Rejected(已失敗)。
(1)默認的Promise對象是等待態(Pending)。
只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
這也是Promise這個名字的由來,它的英語意思就是“許諾”,表示其他手段無法改變。
(2)一旦狀態改變了,就不會再變了,會一直保持這個結果。
任何時候都可以得到這個結果。
Promise對象的狀態改變,只有兩種:
從Pending變為Resolved。 從Pending變為Rejected。
這與事件(Event)不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。
用處:
用Promise對象可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。
可以判斷多個異步事件的完成,
Promise缺點:
無法取消Promise,一旦新建它就會立即執行,無法中途取消。
如果不設置回調函數,Promise內部拋出的錯誤,不會反應到外部。
當處于Pending狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
歷史過程
生成promise實例
Promise是一個構造函數,可以生成Promise實例。
接受一個函數A作為參數,該函數A有2個參數,是resolve和reject(拒絕),它們是函數,由JS引擎提供,不用自己部署。
resolve(value)函數的作用是,將Promise對象的狀態從“未完成”變為“成功”(即從Pending變為Resolved),在異步操作成功時被調用,并將異步操作的結果,作為自己的參數。
reject(error)函數的作用是,將Promise對象的狀態從“未完成”變為“失敗”(即從Pending變為Rejected),在異步操作失敗時調用,并將異步操作報出的錯誤,作為自己的參數。
reject函數的參數通常是Error對象的實例,表示拋出的錯誤。
例子:
reject(new Error(this.statusText));
在promise實例的構造函數中,可以只返回resolve(value)或reject(error);
例子:
let pro = new Promise((resolve,reject)=>{resolve(value)});
寫法:
創造了一個Promise實例。
const promise = new Promise(function(resolve, reject) { if ( /* 異步操作成功 */ ) { resolve(value); } else { reject(error); } });
promise實例的then()方法
這個方法在實例的狀態改變時會觸發它的參數函數。
當promise實例轉為成功(Resolved)狀態時,觸發then()的第一個函數參數。
當promise實例轉為失敗(Rejected)狀態時,觸發then()的第二個函數參數。(第二個函數參數可選)
這兩個函數參數都接受promise實例傳出的值作為參數。也就是resolve(value)和reject(value)的value值。
then()方法是定義在原型對象Promise.prototype上的,被所有promise實例繼承。
promise.then( function (value) { // success }, function (value) { // failure } );
箭頭函數方式:
promise.then( (value)=>{}, (error)=>{} )
如果then()中有設置新的promise實例,則then()方法返回這個promise對象。
否則將默認構建一個新的promise對象,并繼承調用then()方法的promise的狀態(成功或失敗)。
then方法return返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。
因此可以采用鏈式寫法,即then方法后面再調用另一個then方法。
這個函數返回undefined,則then()方法構建一個默認的Promise對象,并且這個對象擁有then()方法所屬的Promise對象的狀態。
var p = new Promise(function (resolve) { resolve();//直接標志執行態 }), temp; temp = p.then(function () { //傳入執行態函數,不返回值 }); temp.then(function () { console.log("fulfilled");//擁有p的狀態 }); console.log(temp === p);//默認構建的promise,但已經和p不是同一個對象,輸出false
如果對應狀態所執行的函數返回一個全新的Promise對象,則會覆蓋掉當前Promise,代碼如下:
var p = new Promise(function (resolve) { resolve();//直接標志執行態 }), temp; temp = p.then(function () { //返回新的promise對象,和p的狀態無關 return new Promise(function (resolve, reject) { reject();//標志拒絕態 }); }); temp.then(function () { console.log("fulfilled"); }, function () { console.log("rejected");//輸出rejected });
resolve函數的參數可以是另一個Promise實例
表示當前異步操作的取決于另一個異步操作的結果。
舉個例子來說,張三到李四家拿鑰匙,取決于李四在家不在家。
如果李四在家,那么張三可以成功拿到鑰匙。如果李四不在家,張三就拿不到鑰匙。
有2個promise實例p1和p2,
p2的resolve(p1),那么,p1的狀態決定了p2的狀態。
如果p1的狀態是Pending,那么p2的回調函數就會等待p1的狀態改變,在此之前不會有結果。
如果p1的狀態已經是Resolved或者Rejected,那么p2的回調函數將會立刻執行。
比如像下面這樣。
var p1 = new Promise(function(resolve, reject) { // ...}); var p2 = new Promise(function(resolve, reject) { // ... resolve(p1); })
【】例子:
p1是一個Promise,3秒之后變為rejected。p2的狀態由p1決定,1秒之后,p2調用resolve方法,但是此時p1的狀態還沒有改變,因此p2的狀態也不會變。又過了2秒,p1變為rejected,p2也跟著變為rejected。
var p1 = new Promise(function(resolve, reject) { setTimeout(() => reject(new Error("fail")), 3000); }); var p2 = new Promise(function(resolve, reject) { setTimeout(() => resolve(p1), 1000) }); p2.then(result => console.log(result)) p2.catch(error => console.log(error)) // Error: fail
【】例子:
下面是一個Promise對象的簡單例子。
timeout函數中,會返回新生成的Promise實例,其中,定時器setTimeout會在100ms后調用resolve("done");當調用resolve后,觸發then綁定的回調函數。
zyx456:"done"是resolve的參數。
等效于:
function timeout(ms) { return new Promise((resolve, reject) => { setTimeout(resolve("done"),ms); }); } timeout(100).then((value) => { console.log(value); });
【】例子:
下面是異步加載圖片的例子。
function loadImageAsync(url) {
return new Promise(function(resolve, reject) { var image = new Image(); image.onload = function() { resolve(image); }; image.onerror = function() { reject(new Error("Could not load image at " + url)); }; image.src = url; });
}
【】例子:
下面是一個用Promise對象實現的Ajax操作的例子。
getJSON是對XMLHttpRequest對象的封裝,用于發出一個針對JSON數據的HTTP請求,并且返回一個Promise對象。
var getJSON = function (url) { var promise = new Promise(function (resolve, reject) { var client = new XMLHttpRequest(); client.open("GET", url); client.onreadystatechange = handler; client.responseType = "json"; client.setRequestHeader("Accept", "application/json"); client.send(); function handler() { if (this.readyState !== 4) { return; } if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; }); return promise; }; getJSON("/posts.json").then(function (json) { console.log("Contents: " + json); }, function (error) { console.error("出錯了", error); });
箭頭函數寫法:
getJSON("/post/1.json").then( post => getJSON(post.commentURL)).then( comments => console.log("Resolved: ", comments), err => console.log("Rejected: ", err));
Promise的方法(多種)
Promise.all()
【01】用于將多個Promise實例,包裝成一個新的Promise實例。
接受一個數組作為參數,數組元素都是Promise實例。
如果參數不是Promise實例,會調用Promise.resolve()轉變為Promise實例。
Promise.all()方法的參數不一定是數組,但是必須具有iterator接口,且返回的每個成員都是Promise實例。
【】返回的新的Promise實例的狀態:
所有Promise參數的都變成Resolved,p的狀態才會變成Resolved,參數的返回值組成一個數組,傳遞給p的回調函數。
只要有一個參數被rejected,p的狀態就變成rejected,此時第一個reject的實例的返回值,會傳遞給p的回調函數。
(小z:類似于且操作,且假或真,只有所有的是成功的才可以。你想想,一系列的操作只有都成功才叫成功。)
var p = Promise.all([p1,p2,p3]);
例子
// 生成一個Promise對象的數組 var promises = [2, 3, 5, 7, 8].map(function(id){return getJSON("/post/" + id + ".json");}); Promise.all(promises).then(function(posts) { // ... }).catch(function(reason){ // ... });
Promise.race()
race:賽跑。
【01】將多個Promise實例,包裝成一個新的Promise實例。
返回這個新promise實例,新promise實例的狀態為第一個改變的參數實例的狀態。它的值也是該參數實例傳遞出來的值。
03,參數如果不是Promise實例,就會調用Promise.resolve方法,將參數轉為Promise實例,再進一步處理。
var p = Promise.race([p1,p2,p3]);
例子:
var p = Promise.race([ fetch("/resource-that-may-take-a-while"), new Promise(function (resolve, reject) { setTimeout(() => reject(new Error("request timeout")), 5000) })]) p.then(response => console.log(response)) p.catch(error => console.log(error))
Promise.reject(reason)
【】會返回一個新的Promise實例,該實例的狀態為rejected。
參數reason,會被傳遞給實例的回調函數。
var p = Promise.reject("出錯了"); // 等同于 var p = new Promise((resolve, reject) => reject("foo")) p.then(null, function (s){ console.log(s)});// 出錯了
Promise.resolve(obj)
【01】將對象轉為Promise對象。
如果參數不是具有then方法的對象(又稱thenable對象),則返回一個新的Promise對象,且它的狀態為Resolved。
比如:參數為字符串時,不屬于異步操作(判斷方法是它不是具有then方法的對象),所以等價于Promise構造函數立即執行resolve("str");
03,如果沒有參數,可以得到一個Promise對象。
04,如果參數是一個Promise實例,則會被原封不動地返回。
var jsPromise = Promise.resolve($.ajax("/whatever.json"));
Promise.resolve等價于下面的寫法。
Promise.resolve("foo") // 等價于 new Promise(resolve => resolve("foo"))
例子:
var p = Promise.resolve("Hello"); p.then(function (s){console.log(s)});// Hello
例子:
var p = Promise.resolve(); p.then(function () { // ...});
Promise.prototype.catch()的概念
【01】是 promise實例.then(null, rejection) 的別名,用于指定發生錯誤時的回調函數。
【】例子:
getJSON方法返回一個Promise對象,如果該對象狀態變為Resolved,則會調用then方法指定的回調函數;
如果異步操作拋出錯誤,狀態就會變為Rejected,就會調用catch方法指定的回調函數,處理這個錯誤。
getJSON("/posts.json").then(function(posts) { // ... }).catch(function(error) { // 處理前一個回調函數運行時發生的錯誤 console.log("發生錯誤!", error); });
例子:
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));
例子:
Promise拋出一個錯誤,就被catch方法指定的回調函數捕獲。
var promise = new Promise(function(resolve, reject) { throw new Error("test") }); promise.catch(function(error) { console.log(error) });// Error: test
盡量不定義then的reject方法
一般來說,不要在then方法里面定義Reject狀態的回調函數(即then的第二個參數),總是使用catch方法。
第二種寫法要好于第一種寫法,理由是前者更接近同步的寫法(try/catch)。
// bad promise .then(function(data) { // success }, function(err) { // error }); // good promise .then(function(data) { //cb // success }).catch(function(err) { // error });
catch方法返回的還是一個Promise對象,因此后面還可以接著調用then方法。
var someAsyncThing = function() { return new Promise(function(resolve, reject) { // 下面一行會報錯,因為x沒有聲明 resolve(x + 2); }); }; someAsyncThing().catch(function(error) { console.log("oh no", error); }).then(function() { console.log("carry on"); }); // oh no [ReferenceError: x is not defined] // carry on
如果前面的promise和then()沒有報錯,則會跳過catch方法。
Promise.resolve().catch(function(error) { console.log("oh no", error); }).then(function() { console.log("carry on"); }); // carry on
拋錯的冒泡性質
Promise對象的錯誤具有“冒泡”性質,會一直向后傳遞,直到被捕獲為止。
也就是說,錯誤總是會被下一個catch語句捕獲。
例子:
一共有三個Promise對象:一個由getJSON產生,兩個由then產生。它們之中任何一個拋出的錯誤,都會被最后一個catch捕獲。
getJSON("/post/1.json").then(function(post) {
return getJSON(post.commentURL); }).then(function(comments) { // some code
}).catch(function(error) { // 處理前面三個Promise產生的錯誤
});
如果Promise狀態已經變成resolved,再拋出錯誤是無效的。
Promise在resolve語句后面,再拋出錯誤,不會被捕獲,等于沒有拋出。
var promise = new Promise(function(resolve, reject) {
resolve("ok");
throw new Error("test"); });
promise.then(function(value) { console.log(value) }).catch(function(error) { console.log(error) });// ok
Promise在下一輪“事件循環”再拋出錯誤
結果由于沒有指定使用try...catch語句,就冒泡到最外層,成了未捕獲的錯誤。
因為此時,Promise的函數體已經運行結束了,所以這個錯誤是在Promise函數體外拋出的。
var promise = new Promise(function(resolve, reject) { resolve("ok"); setTimeout(function() { throw new Error("test") }, 0) }); promise.then(function(value) { console.log(value) }); // ok // Uncaught Error: test
如果沒有處理錯誤的回調函數,就沒有反應
跟傳統的try/catch代碼塊不同的是,如果沒有使用catch方法指定錯誤處理的回調函數,Promise對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應。
someAsyncThing函數產生的Promise對象會報錯,但是由于沒有指定catch方法,這個錯誤不會被捕獲,也不會傳遞到外層代碼,導致運行后沒有任何輸出。
var someAsyncThing = function() { return new Promise(function(resolve, reject) { // 下面一行會報錯,因為x沒有聲明 resolve(x + 2); }); }; someAsyncThing().then(function() { console.log("everything is great"); });
catch方法之中,還能再拋出錯誤。
catch方法拋出一個錯誤,因為后面沒有別的catch方法了,導致這個錯誤不會被捕獲,也不會傳遞到外層。
var someAsyncThing = function() { return new Promise(function(resolve, reject) { // 下面一行會報錯,因為x沒有聲明 resolve(x + 2); }); }; someAsyncThing().then(function() { return someOtherAsyncThing(); }).catch(function(error) { console.log("oh no", error); // 下面一行會報錯,因為y沒有聲明 y + 2; }).then(function() { console.log("carry on"); }); // oh no [ReferenceError: x is not defined]
如果改寫一下,結果就不一樣了。
第二個catch方法用來捕獲,前一個catch方法拋出的錯誤。
someAsyncThing().then(function() { return someOtherAsyncThing(); }).catch(function(error) { console.log("oh no", error); // 下面一行會報錯,因為y沒有聲明 y + 2; }).catch(function(error) { console.log("carry on", error); }); // oh no [ReferenceError: x is not defined] // carry on [ReferenceError: y is not defined]
node.js的unhandledRejection
Node.js有一個unhandledRejection事件,專門監聽未捕獲的reject錯誤。
unhandledRejection事件的監聽函數有兩個參數,第一個是錯誤對象,第二個是報錯的Promise實例,它可以用來了解發生錯誤的環境信息。
process.on("unhandledRejection", function (err, p) { console.error(err.stack)});
done()
Promise對象的回調鏈,不管以then方法或catch方法結尾,要是最后一個方法拋出錯誤,都有可能會漏掉(Promise內部的錯誤不會冒泡到全局)。
因此,我們可以提供一個done方法,總是處于回調鏈的尾端,保證拋出任何可能出現的錯誤。
asyncFunc().then(f1).catch(r1).then(f2).done();
done方法的使用,可以像then方法那樣用,提供Fulfilled和Rejected狀態的回調函數,也可以不提供任何參數。但不管怎樣,done都會捕捉到任何可能出現的錯誤,并向全局拋出。
實現代碼:
Promise.prototype.done = function (resolve, reject) { this.then(resolve, reject).catch(function (reason) { // 拋出一個全局錯誤 setTimeout(() => { throw reason }, 0); }); };
finally()
finally方法用于指定不管Promise對象最后狀態如何,都會執行的操作。
它與done方法的最大區別,它接受一個普通的回調函數作為參數,該函數不管怎樣都必須執行。
等效于,運行一個then(),在成功和失敗回調函數中,都要運行callback(),
在Promise.resolve()中運行callback()后,在運行then(),返回結果。
下面是一個例子,服務器使用Promise處理請求,然后使用finally方法關掉服務器。
server.listen(0).then(function () { // run test }).finally(server.stop);
它的實現:
Promise.prototype.finally = function(callback) { return this.then( value => Promise.resolve( callback() ).then(() => value), reason => Promise.resolve(callback()).then(() => {throw reason })); };
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/105517.html
摘要:就稱為部署了遍歷器接口。是一個函數,調用它會生成一個遍歷器對象。它的屬性,也是一個遍歷器對象生成函數,執行后返回它自己。返回遍歷器對象。下面是一個無限運行的遍歷器對象的例子。 『ES6知識點總結』遍歷器iterator本文內容如下: 1 具有iterator接口的數據結構 2 遍歷器過程 3 遍歷器作用: 4 模擬next()方法 5 使用while循環 6 TypeScript的寫法...
摘要:它是語言的第七種數據類型,前六種是布爾值字符串數值對象。在中,根據屬性名來進行判斷。,是一個布爾值,表示該對象使用時,是否可以展開。等同于,指向該對象的默認遍歷器方法,即該對象進行循環時,會調用這個方法,返回該對象的默認遍歷器。 本文字數:3000+,閱讀時間6分鐘。 如果有理解不到位的地方,歡迎大家糾錯。如果覺得還可以,希望大家可以點個贊。 謝謝大家。 目錄 一、Symbol是什么...
摘要:箭頭函數本文字符數,閱讀時間約分鐘左右。箭頭函數等于說,只保留了函數的參數和返回。箭頭函數體內的,繼承的是外層代碼塊的。所以,不用用箭頭函數聲明對象的方法。不可以使用命令因此箭頭函數不能用作函數。 【01】ES6箭頭函數 本文字符數4300+,閱讀時間約8分鐘左右。 【01】箭頭函數 等于說,只保留了函數的參數和返回。省略function和return。 寫法: (形參) => {st...
摘要:命令用于規定本模塊的對外接口。空格模塊名字符串。其他模塊加載該模塊時,命令可以為該匿名函數指定任意名字。寫法函數聲明命令用在非匿名函數前,也是可以的。加載的時候,視同匿名函數加載。 本文字符數8200+,閱讀時間約16分鐘。 『ES6知識點總結』模塊Module 第一節:Module基本概念 【01】過去使用CommonJS和AMD,前者用于服務器,后者用于瀏覽器。 Module可以取...
摘要:返回一個布爾值,表示該值是否為的成員。清除所有成員,沒有返回值。返回的都是遍歷器對象。結構的實例的方法,用于對每個成員執行某種操作,沒有返回值。這個特點意味著,無法引用的成員,因此是不可遍歷的。數組成員是一個或多個表示鍵值對的一維數組。 本文字數:4700+,閱讀時間約10分鐘。 如果有理解不到位的地方,歡迎大家糾錯。 一、Set 【01】Set是一種數據結構。類似于數組,但是成員的值...
閱讀 6912·2021-09-22 15:08
閱讀 1920·2021-08-24 10:03
閱讀 2437·2021-08-20 09:36
閱讀 1315·2020-12-03 17:22
閱讀 2474·2019-08-30 15:55
閱讀 905·2019-08-29 16:13
閱讀 3053·2019-08-29 12:41
閱讀 3249·2019-08-26 12:12