『ES6知識點總結』變量的解構賦值node
本文主要內容以下:
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()ajax
Promise是什麼?
0一、是一個對象,用來傳遞異步操做的消息。
0二、表明了某個將來纔會知道結果的事件(一般是一個異步操做)。
0三、提供一個統一的API,能夠進一步處理,控制異步操做。json
特色:數組
0一、對象的狀態不受外界影響。promise
0二、表明一個異步操做。服務器
三種狀態:app
Pending(進行中) Resolved(已完成,又稱Fulfilled) Rejected(已失敗)。
(1)默認的Promise對象是等待態(Pending)。
只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態。
這也是Promise這個名字的由來,它的英語意思就是「許諾」,表示其餘手段沒法改變。異步
(2)一旦狀態改變了,就不會再變了,會一直保持這個結果。
任什麼時候候均可以獲得這個結果。async
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 })); };