Promise 簡單來說是非同步程式設計的一種解決方案
Promise物件有以下兩個特點:
(1)物件的狀態不受外界影響。Promise物件代表一個非同步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。只有非同步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。
(2)一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise物件的狀態改變,只有兩種可能:從pending變為fulfilled和從pending變為rejected。只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果。
(3)有了Promise物件,就可以將非同步操作以同步操作的流程表達出來,避免了層層巢狀的回撥函式。
promise的寫法
let mypromise=new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(100)
},1000);
});
mypromise.then((res)=>{
console.log(res);
},()=>{
console.log("no");
})
複製程式碼
用promise寫Ajax
let pro=new Promise((resolve,reject)=>{
let xhr=new XMLHttpRequest();
xhr.open("get","js/1.js",true);
xhr.onreadystatechange=()=>{
if(xhr.readyState===4 && xhr.status===200){
val=xhr.responseText;
resolve(val);
}
if(xhr.status!==200){
reject();
}
};
xhr.send();
});
pro.then((res)=>{
console.log(res);
獲取資料//資料繫結
},()=>{
console.log("no不行");
})
複製程式碼
這樣一來管理回撥函式或者非同步事件就很清楚了。可以後面繼續追加.then();
then中兩個方法,成功走第一個,失敗走第二個,
比如實現某一種效果,就比如商品排序。
第一個then請求資料,繫結資料,渲染資料
第二個then從小到大排序
第三個then從大到小排序
let op=new Promise((resolve,reject)=>{
//Ajax請求資料
})
op.then((res)=>{
繫結資料//渲染資料
},()=>{
}).then(()=>{
//商品排序
})
...以此內推
複製程式碼
一旦在第一個then中return了,那麼返回結果就給了第二個then,以此內推。
這種設計模式,功能很強大,也方便了許多,從上面可以看出 .then()可以寫很多個,那麼promise的實現原理是什麼呢?
接下來就小手擼程式碼,進入正題
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
class MyPromise{
constructor(excutor){
// 這裡相當於MyPromise的函式體;
// 在promise中分三個狀態;pending fulfilled rejected;
// this --> promise的例項;給例項新增state屬性,其屬性值是"pending";
this.state="pending";
// 在例項上找了兩塊空間;一個是用來儲存成功的回撥,一個用來儲存失敗的回撥;
this.fulfilledEvent = [];
this.rejectedEvent = [];
this.value =undefined;
let resolve = (result)=>{
// resolve : 這個函式是用來管控所有成功態的函式執行;
// 一旦呼叫resolve,那麼應該變成成功態;
//if(this.state==="fulfilled"||this.state==="rejected")return;
// 如果當前狀態已經凝固,是成功或者失敗中的一個,都不再執行;
if(this.state!=="pending")return;
this.state="fulfilled";
this.value=result;
clearTimeout(this.timer);
this.timer = setTimeout(()=>{
this.fulfilledEvent.forEach((item)=>{
if(typeof item==="function"){
item(this.value);
}
})
},0)
};
let reject=(result)=>{
if(this.state!=="pending")return;
this.state="rejected";
clearTimeout(this.timer);
this.value=result;
this.timer = setTimeout(()=>{
this.rejectedEvent.forEach((item)=>{
if(typeof item==="function"){
item(this.value);
}
})
},0)
}
try{
excutor(resolve,reject)
}catch(e){
// 如果在函式中丟擲異常,那麼會呼叫下面then的reject的方法;
reject(e);
}
}
then(resolveFn,rejectedFn){
if(resolveFn===undefined){
//如果then沒有傳遞函式,那麼給當前預設賦值一個函式
resolveFn=(result)=>{
return result
}
}
if(rejectedFn===undefined){
rejectedFn=()=>{
// 這個地方丟擲異常,為了能夠呼叫下個then的失敗的方法;
throw new Error;
}
}
// 為了確保下一次的then方法中的回撥受上一次then方法中返回值的影響,
//所以每次呼叫then,都返回一個不同的例項;
return new MyPromise((resolve,reject)=>{
// this --> then中this--> p1;
this.fulfilledEvent.push(()=>{
// 需要驗證當前resolveFn函式的返回值是否是一個Promise的例項;
try{
let x = resolveFn();
x instanceof MyPromise?x.then(resolve,reject):resolve();
}catch(e){
reject(e)
}
});
this.rejectedEvent.push(()=>{
try{
let x = rejectedFn();
x instanceof MyPromise?x.then(resolve,reject):resolve();
}catch(e){
reject(e)
}
});
});
}
}
let p1 = new MyPromise(function (resolve,reject) {
resolve(200)
})
console.log(1);
let p2=p1.then(function (res) {
return new MyPromise(function (resolve,reject) {
reject();
})
},function () {
console.log(101);
});
p2.then(function () {
console.log(11);
},function () {
console.log(22);
})
</script>
</body>
</html>
複製程式碼
注意:
- 當new 一個promise時,promise中的函式會立馬執行
- 當promise的狀態一旦固定,就不再改變
- 無法取消Promise,一旦新建它就會立即執行,無法中途取消
- 如果不設定回撥函式,Promise內部丟擲的錯誤,不會反應到外部
- 當處於pending狀態時,無法得知目前進展到哪一個狀態
then方法
- then : 為promise的例項增加狀態發生改變時的回撥函式
- then: 把第一個then中的回撥的返回值會傳遞給第二個then回撥的函式的形參
- then : 方法中內建會返回一個新的promise的例項;但不是之前的那個promise的例項了
- 前面一個回撥函式中如果返回一個promise的物件,那麼第二個回撥函式會等待第一個返回的promise例項的狀態發生變化才執行
promise的catch
- catch : 捕獲當前非同步的錯誤資訊
- 如果在catch之前已經有then將錯誤資訊進行處理,那麼不再執行這個catch方法
- 如果第一個請求失敗,那麼不會再執行第二個請求
- catch : 只要之前的請求有一個失敗,都會觸發這個catch方法
promise的all
- all : 是將多個Promise的例項包裝成一個promise的例項
- all方法是Promise這個類的私有方法
- all方法傳遞一個陣列,陣列中存放著Promise的例項;all方法返回一個promise的例項
- p1的成功或者失敗的狀態由陣列中每一個promise的例項決定;當所有的例項的狀態都是成功態,那麼該p1的狀態才是成功態,只要有一個失敗,那麼這個就會執行失敗態
let p1 = Promise.all([l1,l2,l3]).then(function () {},function () {})
複製程式碼