1.Promise
Promise是目前比較流行的非同步解決方案,本質上一個建構函式。
1.1狀態
promise有三種狀態,初始狀態是pedding,包括:
- 成功狀態 pedding => resolve
- 失敗狀態 pedding => reject
- 等待狀態 pedding
我們先來看一個簡單的例子
let promise = new Promise(function(resolve,reject){
//throw new Error('出錯了')
//resolve()
reject()
});
promise.then(()=>{
console.log('success')
},()=>{
console.log('error');
});
複製程式碼
每個promise的例項都有then方法,包額括兩個引數,分別是成功的回撥會失敗的回撥,同時支援多次then,成功就回撥所有成功方法失敗也是如此,本質上then是一個非同步的,也稱為微任務。 其他方法還包括:
- Promise.all() 所有的promise物件成功才會觸發成功狀態,否則失敗狀態
- Promise.race() 任意一個子pormise的狀態觸發後會被父promise立即呼叫,完成一個即可
2. 自己實現一個Promise
所有的promise都要遵循promiseA+規範
2.1簡易版
function Promise(executor){
let self = this;
self.value = undefined; //定義成功的value
self.reason = undefined; //定義失敗的reson
self.status = 'pending'; //初始化狀態為pedding
function resolve(value){
if(self.status === 'pending'){ //只有pedding的時候狀態才可以改變
self.value = value;
self.status = 'resolved';
}
}
function reject(reason){
if(self.status === 'pending'){ //只有pedding的時候狀態才可以改變
self.reason = reason;
self.status = 'rejected';
}
}
// 如果函式執行時發生異常throw new Error,就失敗
try{
executor(resolve,reject); //executor 預設new的時候就自動執行
}catch(e){
reject(e);
}
}
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
//判斷當前狀態
// 成功狀態時
if(self.status === 'resolved'){//如果成功,執行成功,並把成功原因傳過去
onFulfilled(self.value);//上面的例項then中成功回撥(console.log('success'))
}
// 失敗狀態時
if(self.status === 'rejected'){//如果失敗,執行失敗,並把失敗原因傳過去
onRejected(self.reason);//上面的例項then中失敗回撥(console.log('error'))
}
}
module.exports = Promise;
複製程式碼
2.2 稍微完善
但當在new Promise 中加入有非同步方法,如下3秒後才開始執行成功,此時resolve會延遲執行,then中的狀態又不是成功,又不是失敗,因此會不執行成功或者失敗方法,因為需要將成功或者失敗的方法用陣列存起來
let promise = new Promise(function(resolve,reject){
setTimeout(()=>{
resolve()
},3000)
});
複製程式碼
來完善的例子
function Promise(executor){
let self = this;
self.value = undefined;
self.reason = undefined;
self.status = 'pending';
self.onResolvedCallbacks = [];// 存放then中成功的回撥
self.onRejectedCallbacks = []; // 存放then中失敗的回撥
function resolve(value){
if(self.status === 'pending'){
self.value = value;
self.status = 'resolved';
self.onResolvedCallbacks.forEach(fn=>fn());//迴圈執行成功
}
}
function reject(reason){
if(self.status === 'pending'){
self.reason = reason;
self.status = 'rejected';
self.onRejectedCallbacks.forEach(fn=>fn());//迴圈執行失敗
}
}
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
}
// onFulfilled成功的回撥 onRejected失敗的回撥
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
if(self.status === 'pending'){//當等待狀態時候,儲存回撥函式
self.onResolvedCallbacks.push(()=>{
onFulfilled(self.value);
});
self.onRejectedCallbacks.push(()=>{
onRejected(self.reason)
});
}
}
module.exports = Promise;
複製程式碼
2.3 鏈式呼叫
我們知道Promise可以一直then下去,來實現鏈式呼叫,但上面的例子明顯不可以實現 例如
let p = new Promise((resolve,reject) =>{
resolve(123)
})
let p1 = new Promise((resolve,reject) =>{
resolve(111)
})
p.then((data)=>{
console.log(data)
return p1 //返回的p1是一個新的promise,繼續成功下去,把111傳給下一個newData,失敗也是如此,如果返回的是普通值,直接把值作為下一層then的引數,所以需要判斷p1是不是promise
}).then((newData)=>{
console.log('p1',data)
})
複製程式碼
完善程式碼
function Promise(executor) {
let self = this;
self.value = undefined;
self.reason = undefined;
self.status = 'pending';
self.onResolvedCallbacks = [];
self.onRejectedCallbacks = [];
function resolve(value) {
if (self.status === 'pending') {
self.value = value;
self.status = 'resolved';
self.onResolvedCallbacks.forEach(fn => fn());
}
}
function reject(reason) {
if (self.status === 'pending') {
self.reason = reason;
self.status = 'rejected';
self.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
/**
*
* @param {*} promise2 then的返回值 (返回的新的promise)
* @param {*} x then中成功或者失敗函式的返回值
* @param {*} resolve promise2的resolve
* @param {*} reject promise2的reject
*/
function resolvePromise(promise2,x,resolve,reject){
// promise2和函式執行後返回的結果是同一個物件,自己等待自己執行,不可以
<!--例如 let p1 = p.then((data)=>{-->
<!-- return p1 //返回的promise既不會成功也不會失敗,自己等待自己-->
<!--})-->
if(promise2 === x){
return reject(new TypeError('Chaining cycle'));
}
let called;
// x可能是一個promise 或者是一個普通值
if(x!==null && (typeof x=== 'object' || typeof x === 'function')){
try{
let then = x.then; // 這個promise可能是別人亂寫的,所以try catch
// x可能還是一個promise 那麼就讓這個promise執行即可
if(typeof then === 'function'){
then.call(x,y=>{ // 返回promise後的成功結果
// 遞迴直到解析成普通值為止
if(called) return; // 防止多次呼叫
called = true;
// 遞迴 可能成功後的結果是一個promise 那就要迴圈的去解析
resolvePromise(promise2,y,resolve,reject);
},err=>{ // promise的失敗結果
if(called) return;
called = true;
reject(err);
});
}else{
resolve(x);
}
}catch(e){
if(called) return;
called = true;
reject(e);
}
}else{ // 如果x是一個常量
resolve(x);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
let promise2;
// 需要每次呼叫then時都返回一個新的promise
promise2 = new Promise((resolve, reject) => {//相當於調完了then又返回了一個promise
if (self.status === 'resolved') {
setTimeout(()=>{
try {
// 當執行成功回撥的時候可能會出現異常,那就用這個異常作為promise2的錯誤的結果
let x = onFulfilled(self.value); //新的promise,也就是then的返回結果
//執行完當前成功回撥後返回結果可能是promise
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
}
// 規範要求加setTimeout
if (self.status === 'rejected') {
setTimeout(()=>{
try {
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
}
if (self.status === 'pending') {//等待的時候也要包裝一個promise2
self.onResolvedCallbacks.push(() => {
setTimeout(()=>{
try {
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
});
self.onRejectedCallbacks.push(() => {
setTimeout(()=>{
try {
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0)
});
}
});
return promise2
}
module.exports = Promise;
複製程式碼