Promise
Promise
是一門新的技術(ES6規范),JS中進行異步編程的新解決方案。(舊的方案是使用回調函數,比如AJAX請求)。
從語法上來說Promise
是一個構造函數。
從功能上來說Promise
對象用來封裝一個異步操作并可以獲取其成功/失敗的結果值。
Promise初體驗
<script>//普通實現異步方法setTimeout()const btn = document.querySelector('#btn');btn.addEventListener('click',()=>{setTimeout(()=>{alert('1秒后執行');},1000);});document.querySelector('#btn1').addEventListener('click',()=>{//使用Promise//1. resolve 函數類型數據,異步執行成功回調//2. reject 函數類型數據,異步執行失敗回調const promise = new Promise((resolve,reject)=>{setTimeout(()=>{//獲取1-10的隨機數let n = Math.floor(Math.random() * (10 - 1 + 1)) + 1;if(n <= 5){resolve(n); //將promise對象狀態設置為 成功console.log('resolve');}else{reject(n);//將promise對象狀態設置為 失敗console.log('resolve');}},1000);});//調用then方法獲取異步函數執行狀態,執行的是resolve/reject//接受兩個函數 resolve & rejectpromise.then((val)=>{alert('resolve ' + val);},(val)=>{alert('reject ' + val);});});</script>
catch方法
const promise = new Promise((resolve,reject)=>{//獲取1-10的隨機數let n = Math.floor(Math.random() * (10 - 1 + 1)) + 1;if(n<=5){resolve(n);}else{reject(n);}}).then((val)=>{console.log('success' + val);}).catch((err)=>{console.log('failure' + err);});
使用Promise封裝AJAX請求
const btn = document.querySelector('#btn');btn.addEventListener('click',()=>{const promise = sendAJAX('http://localhost/test');//調用then方法promise.then((val)=>{//成功console.log(val);},(val)=>{//失敗console.log(val);});});function sendAJAX(url){const promise = new Promise((resolve,reject)=>{//1. AJAX請求 , 創建http客戶端const http = new XMLHttpRequest();//2. 初始化http.open('GET',url);//3. 發送請求http.send();//4. 處理響應結果http.onreadystatechange = function(){if(http.readyState === 4){if(http.status == 200){//成功resolve(http.response);}else{//失敗reject(http.status);}}}});return promise;}
Promise屬性
PromiseState:Promise狀態
- pending:等待,初始化默認值
- resolved / fullfilled:表示成功
- rejected:表示失敗
PromiseResult:保存著對象的結果。成功/失敗
- resolve():resolve方法會把狀態改為成功,并且存成功的結果
- reject():reject方法會把狀態改為失敗,并且保存失敗結果
Promise方法
- Promise.resolve()方法:如果傳入的參數是非Promise類型的對象,則返回結果是成功的Promise對象,如果傳入的參數為Promise對象,則參數的結果決定了resolve的結果
let promise = Promise.resolve(1);console.log(promise);promise = Promise.resolve(new Promise((resolve,reject)=>{//resolve();reject();}));console.log(promise);
- Promise.reject()方法:快速的返回一個失敗的Promise對象,無論傳入什么,返回結果都是失敗。
let promise = Promise.reject(1) console.log(promise);
- Promise.all()方法:傳入Promise數組,只有所有的Promise對象都成功才成功,只要有一個失敗就直接失敗。成功的返回結果是全部的Promise對象。無論有多少個失敗,都會執行完全部的Promise。
const p1 = new Promise((resolve,reject)=>{resolve();console.log(1)})const p2 = new Promise((resolve,reject)=>{reject();console.log(2)})const p3 = new Promise((resolve,reject)=>{reject();console.log(3)})let promises = Promise.all([p1,p2,p3])console.log(promises);
- Promise.race()方法:傳入Promise數組,第一個完成的Promise的結果的狀態就是最終的結果狀態。結果也是第一個成功返回的結果。
const p1 = new Promise((resolve,reject)=>{resolve();console.log(1)})const p2 = new Promise((resolve,reject)=>{reject();console.log(2)})const p3 = new Promise((resolve,reject)=>{reject();console.log(3)})let promises = Promise.race([p1,p2,p3])console.log(promises);
Promise關鍵知識
- 如何改變Promise狀態
const promise = new Promise((resolve,reject)=>{//1. 調用resolve()方法,改為成功狀態resolve();//2. 調用reject()方法,改為失敗狀態reject();//3. 拋出一個異常改為失敗狀態 throwthrow 'has error';})
- 可以為Promise指定多個then函數,都會被執行
const promise = new Promise((resolve,reject)=>{resolve();}).then(()=>{console.log(1);}).then(()=>{console.log(2);}).then(()=>{console.log(3);});
- then和catch函數,是執行器里執行reslove()或者reject()方法才會執行
const promise = new Promise((resolve,reject)=>{setTimeout(()=>{console.log('setTimeout');resolve();},2000)}).then(()=>{console.log(1);}).then(()=>{console.log(2);}).then(()=>{console.log(3);});
Promise鏈式調用
Promise的then方法可以返回Promise對象,當返回Promise對象時,后續的then方法接受到的參數是上一個then返回Promise返回的對象的返回值,如下。
也就是說,可以實現對異步操作的鏈式調用,只用上一個異步執行接受,有返回值的時候才會執行下一個then,不需要自己去判斷線程的狀態。
//三個異步方法,最后輸出為 1 2 3const promise = new Promise((resolve,reject)=>{//1. 第一個異步方法setTimeout(()=>{resolve(1);},2000)}).then((val)=>{console.log(val);return new Promise((resolve,reject)=>{//2. 第二個異步方法setTimeout(()=>{resolve(2);},1000)})}).then((val)=>{console.log(val);return new Promise((resolve,reject)=>{//3. 第三個異步方法setTimeout(()=>{resolve(3);},1000)})}).then((val)=>{console.log(val);});
鏈式調用的異常穿透
鏈式調用過程中,只需要有一個catch,如果其中某一環節出錯,拋出異常throw 'error msg'
,則會執行catch的函數,不會繼續執行接下來的任務。
const promise = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(1);},2000)}).then((val)=>{console.log(val);return new Promise((resolve,reject)=>{setTimeout(()=>{//拋出異常直接執行catch,不會執行繼續執行,因為沒有執行到resolve()方法throw 'error';resolve(2);},1000)})}).then((val)=>{console.log(val);return new Promise((resolve,reject)=>{setTimeout(()=>{resolve(3);},1000)})}).then((val)=>{console.log(val);}).catch(err=>{console.log(err);});
中斷鏈式調用
- 中斷鏈式調用的方法是返回一個空函數的Promise對象
new Promise(()=>{})
這樣就不會跳入下一個then里面 - 在某些業務場景中可以拋出異常來中斷Promise,如上異常穿透也是終止了鏈式調用。這種直接調用了catch,也屬于另類的終止
promise = new Promise((resolve,reject)=>{setTimeout(()=>{resolve(1);},2000)}).then((val)=>{console.log(val);//終止鏈式調用return new Promise(()=>{})}).then((val)=>{console.log(2);return new Promise((resolve,reject)=>{setTimeout(()=>{resolve(3);},1000)})}).then((val)=>{console.log(val);}).catch(err=>{console.log(err);});