特點(diǎn)
Promise能將回調(diào)分離出來(lái),在異步操作執(zhí)行之后,用鏈?zhǔn)椒椒▓?zhí)行回調(diào),雖然es5用封裝函數(shù)也能實(shí)現(xiàn),但是如果有多層異步的話,就會(huì)顯得比較繁瑣,而Promise用鏈?zhǔn)絼t更加直觀優(yōu)雅.
Promise對(duì)象不受外界的影響.有三種狀態(tài).
pending
進(jìn)行中,fulfilled
已成功,rejected
已失敗.只有異步操作的結(jié)果可以決定當(dāng)前是哪一種狀態(tài).狀態(tài)一旦改變,就不會(huì)再變.
語(yǔ)法
Promise 譯為承諾,即為如果我做到了,會(huì)怎么怎么樣,沒做到,會(huì)怎么怎么樣,es6中的promise大致表達(dá)的意思也是這樣,用于一個(gè)異步操作最終完成或者沒完成及其結(jié)果的表示.
- 語(yǔ)法
var promise = new Promise( //executor function(resolve,reject){ if(/*異步成功*/){resolve(value)} else{reject(error)} } ) promise.then(function(value){ //success },funtion(){ //fail })
參數(shù)
參數(shù): 為回調(diào)函數(shù),回調(diào)函數(shù)的參數(shù)為resolve和reject
resolve和reject分別表示異步操作成功后的回調(diào)函數(shù)和異步操作失敗的回調(diào)函數(shù),
resolve函數(shù),將Promise的狀態(tài)改為fulfilled;reject改為rejected;
Promise實(shí)例創(chuàng)建成功后,
then
方法分別指定不同狀態(tài)的回調(diào)函數(shù)
參數(shù)executor補(bǔ)充點(diǎn)
-
回調(diào)函數(shù)executor在Promise構(gòu)造函數(shù)執(zhí)行的時(shí)候同步執(zhí)行
//注意打印結(jié)果的順序 let pro = new Promise(function(resolve,reject){ console.log('inPromise') resolve('成功后的回調(diào)') }); pro.then((data) => console.log(data)) console.log('notInPromise') // inPromise // notInPromise // '成功后的回調(diào)'
同步執(zhí)行是什么意思呢,以上代碼中,我只是new了一個(gè)實(shí)例
pro
,但是并沒有去調(diào)用pro
,最終結(jié)果仍然打印出了內(nèi)容,因?yàn)閚ew的過(guò)程和executor的執(zhí)行是同時(shí)的,所以在創(chuàng)建實(shí)例的時(shí)候,回調(diào)函數(shù)就已經(jīng)在執(zhí)行了.-
有時(shí)候我們只是想創(chuàng)建實(shí)例,并不想去執(zhí)行,該怎么辦呢?一般的解決辦法就是把它包裝在一個(gè)函數(shù)中.需要使用的時(shí)候再去執(zhí)行這個(gè)包裝函數(shù).
function promisBox(){ let pro = new Promise(function(resolve,reject){ console.log('inPromise') resolve('成功后的回調(diào)') }); console.log('notInPromise') return pro; } promisBox().then((data) => console.log(data))
基本用法
promise.then(onFulfilled, onRejected)
如果 onFulfilled, onRejected不是函數(shù),其必須被忽略;若為函數(shù),僅可被調(diào)用一次!
onFulfilled在Promise執(zhí)行結(jié)束前不可被調(diào)用.
onRejected在被拒絕執(zhí)行前不可被調(diào)用.
-
創(chuàng)建實(shí)例之后,調(diào)用.then,then可以接收兩個(gè)回調(diào)函數(shù)當(dāng)作參數(shù).第一個(gè)參數(shù)是異步執(zhí)行成功的時(shí)候調(diào)用,第二個(gè)則為失敗的時(shí)候調(diào)用,可省略.
//還用上面的例子 function promisBox(age){ let pro = new Promise(function(resolve,reject){ if(age > 18){ resolve('成功后的回調(diào)') }else{ reject('失敗后的回調(diào)') } }); return pro; } promisBox(24).then( (res) => console.log(res), //接收上面resolve中的參數(shù) (error) => console.log(error) //接收上面reject中的參數(shù) ) //'成功后的回調(diào)' promisBox(17).then( (res) => console.log(res), //接收上面resolve中的參數(shù) (error) => console.log(error) //接收上面reject中的參數(shù) ) //'失敗后的回調(diào)'
-
除了then之外,還有catch方法;catch和then里的第二個(gè)參數(shù)效果一樣,不過(guò)多了一個(gè)功能,如果then第一個(gè)參數(shù)內(nèi)代碼出錯(cuò),并不會(huì)報(bào)錯(cuò)卡死,而是會(huì)進(jìn)到catch方法內(nèi).
function promisBox(age){ let pro = new Promise(function(resolve,reject){ if(age > 18){ resolve('成功后的回調(diào)') }else{ reject('失敗后的回調(diào)') } }); return pro; } promisBox(24) .then( (res) => console.log(xixi,res), //xixi變量沒有定義,進(jìn)入到catch方法,不報(bào)錯(cuò) ) .catch(error => console.log(error)) //接收then第一個(gè)參數(shù)內(nèi)的報(bào)錯(cuò)信息 // failed // ReferenceError: xixi is not defined...
小例子
-
案例1
var promise2 = new Promise((resolve,reject) => { setTimeout(function (){resolve('success')},250) }) promise2.then((suc) => console.log(suc)) // 'success'
-
案例2(摘自阮一峰老師,鏈接在最后)
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('出錯(cuò)了', error); });
對(duì)象方法
Promise.prototype.then()
-
如果有多層異步和回調(diào)
function promisBox(){ let pro = new Promise(function(resolve,reject){ console.log('inPromise1') resolve('成功后的回調(diào)1') }); console.log('notInPromise1') return pro; } function promisBox2(){ let pro = new Promise(function(resolve,reject){ console.log('inPromise2') resolve('成功后的回調(diào)2') }); console.log('notInPromise2') return pro; } promisBox() .then((res) => {console.log(res);return promisBox2()}) .then((res) => {console.log(res);return '也可以直接返回?cái)?shù)據(jù),作為參數(shù)'}) .then((res) => {console.log(res)}) //inPromise1 //notInPromise1 // 成功后的回調(diào)1 // inPromise2 // notInPromise2 // 成功后的回調(diào)2 // 也可以直接返回?cái)?shù)據(jù),作為參數(shù)
-
一個(gè)異步的結(jié)果返回另一個(gè)異步操作
var promise1 = new Promise((resolve,reject) => { setTimeout(() => reject('reject'),3000) }) var promise2 = new Promise((resolve,reject) => { setTimeout(() => resolve(promise1),1000) } ) promise2 //這里的then語(yǔ)句是promise1的事件了 .then(res => console.log('success',res)) .catch(error => console.log('failed',error)) //三秒之后 打印出 'failed reject'
promise1的狀態(tài)決定了promise2的狀態(tài),所以這個(gè)時(shí)候,所以沒有執(zhí)行promise1的resolve函數(shù)
Promise.prototype.catch()
Promise.prototype.catch() 等同于.then(null,reject)
-
以下兩種寫法效果一樣,一般用第二種方法
// 一 var promise = new Promise(function(resolve, reject) { console.log(xixixixi) }); promise .then(null,err => console.log('reject',err)) // 二 promise .catch(err => console.log('reject',err)) // reject // ReferenceError: xixixixi is not defined
-
Promise實(shí)例在resolve之后再有錯(cuò)誤,不會(huì)被捕獲.
var promise = new Promise(function(resolve, reject) { resolve('success') console.log(xixixixi) }); promise .then(res => console.log(res)) .catch(err => console.log(err)) // success
-
任意一個(gè)then發(fā)生錯(cuò)誤的時(shí)候,都會(huì)被最后的catch捕獲到
promise .then(res => console.log(res)) .then(res => console.log(res)) .then(res => console.log(res)) .catch(err => console.log(err)) //以上三個(gè),任意一個(gè)出現(xiàn)錯(cuò)誤,都會(huì)被捕捉
-
catch返回的是Promise,所以之后可以繼續(xù).then
var promise = new Promise(function(resolve, reject) { console.log(xixixixi) }); promise .catch(err => console.log(err)) .then(res => console.log('繼續(xù)執(zhí)行')) // ReferenceError: xixixixi is not defined // 繼續(xù)執(zhí)行
-
上例換個(gè)順序
var promise = new Promise(function(resolve, reject) { resolve('隨便') }); promise .catch(err => console.log(err)) .then(res => {console.log(res);console.log(xixixi)}) //.catch(err => console.log(err)) // 先打印出 '隨便' // 然后拋出錯(cuò)誤 ReferenceError: xixixi is not defined; // 之前都是打印出錯(cuò)誤,不影響運(yùn)行.這里是拋出錯(cuò)誤,停止運(yùn)行 // 因?yàn)檫@里的then出現(xiàn)錯(cuò)誤,跟之前的catch無(wú)關(guān)了,錯(cuò)誤無(wú)法被捕獲
Promise.all()
Promise.all(iterable);
只有參數(shù)中的每個(gè)實(shí)例的狀態(tài)都編程fulfilled或者其中一個(gè)變?yōu)閞ejected,才會(huì)調(diào)用之后的回調(diào)函數(shù)
-
首先看一段代碼,了解用法,還是用上面promiseBox的例子,下例中,參數(shù)為 promisBox 和 promisBox2 組成的數(shù)組,all的狀態(tài)是由數(shù)組中的值共同決定,只有每個(gè)值的狀態(tài)都是fulfilled,all的狀態(tài)才會(huì)變成fulfilled.返回值為一個(gè)數(shù)組.
function promisBox(){ let pro = new Promise(function(resolve,reject){ resolve('成功后的回調(diào)1') }); return pro; } function promisBox2(){ let pro = new Promise(function(resolve,reject){ resolve('成功后的回調(diào)2') }); return pro; } var all = Promise.all([promisBox(),promisBox2()]) .then((res) => console.log(res)) .catch(err => console.log(err)) // ["成功后的回調(diào)1", "成功后的回調(diào)2"]
-
數(shù)組中有一個(gè)值的狀態(tài)為rejected,則all的狀態(tài)為rejected
function promisBox(){ let pro = new Promise(function(resolve,reject){ resolve('成功后的回調(diào)1') }); return pro; } function promisBox2(){ let pro = new Promise(function(resolve,reject){ resolve('成功后的回調(diào)2') }); return pro; } function promisBox3(){ let pro = new Promise(function(resolve,reject){ console.log(xixixixi) resolve('成功后的回調(diào)3') }); return pro; } var all = Promise.all([promisBox(),promisBox2(),promisBox3()]) .then((res) => console.log(res)) .catch(err => console.log(err)) //ReferenceError: xixixixi is not defined
-
如果參數(shù)實(shí)例中自己定義了catch,如果此參數(shù)的狀態(tài)是rejected,執(zhí)行的是它自己的catch,而不是all的catch
function promisBox(){ let pro = new Promise(function(resolve,reject){ resolve('成功后的回調(diào)1') }); return pro; } function promisBox2(){ let pro = new Promise(function(resolve,reject){ resolve('成功后的回調(diào)2') }); return pro; } function promisBox3(){ let pro = new Promise(function(resolve,reject){ console.log(xixixixi) resolve('成功后的回調(diào)3') }) .catch(err => console.log('promisBox3',err)); return pro; } var all = Promise.all([promisBox(),promisBox2(),promisBox3()]) .then((res) => console.log(res)) .catch(err => console.log('all',err)) // promisBox3 ReferenceError: xixixixi is not defined // ["成功后的回調(diào)1", "成功后的回調(diào)2", undefined]
promisBox3首先是rejected,但是他有自己的catch,通過(guò)catch方法,返回一個(gè)新的Promise實(shí)例,這個(gè)新的實(shí)例狀態(tài)是fulfilled;因此最后all會(huì)執(zhí)行then的回調(diào)
Promise.race()
all的效果是,誰(shuí)執(zhí)行的最慢,就以誰(shuí)為基準(zhǔn)執(zhí)行回調(diào),而race相反,race譯為比賽,效果是誰(shuí)執(zhí)行的快,就以誰(shuí)為基準(zhǔn)去執(zhí)行回調(diào).
race的用法和all差不多.
- 具體例子
function promisBox(){ let pro = new Promise(function(resolve,reject){ //console.log(hahahaha) 第一個(gè)注釋 resolve('成功后的回調(diào)1') }); return pro; } function promisBox2(){ let pro = new Promise(function(resolve,reject){ setTimeout(function(){ //console.log(hahahaha) 第二個(gè)注釋 resolve('成功后的回調(diào)2')} ,2000) }); return pro; } var race = Promise.race([promisBox(),promisBox2()]) .then((res) => console.log(res)) .catch(err => console.log(err)) // 成功后的回調(diào)1 //將第一個(gè)注釋取消 ReferenceError: hahahaha is not defined // 將第二個(gè)注釋取消 '成功后的回調(diào)1' 兩秒后拋出錯(cuò)誤hahahaha is not ...,停止運(yùn)行.