Promise是非同步程式設計的一種解決方案,比回撥函式和事件更合理更強大。
原生的promise用法如下:
let p=new Promise(function(resolve,reject){
resolve('成功');
//reject('失敗');
});
p.then(function(data){
console.log(data);
},function(err){
console.log(err);
});
複製程式碼
Promise例項中有一個函式,接受兩個引數,一個是成功的方法,一個是失敗的方法,然後有一個then方法,第一個是成功執行的函式,第二個是失敗執行的函式,並且會接收相應的引數。一旦執行成功,就不會再執行失敗,反之亦然。
function Promise(executor){ //executor是一個執行函式
let self = this;
self.status = 'pending';
self.value = undefined; //預設成功的值
self.reason = undefined; //預設失敗的值
function resolve(value){ //成功狀態
if(self.status === 'pending'){
self.status = 'resolved';
self.value = value;
}
}
function reject(reason){ //失敗狀態
if(self.status === 'pending'){
self.status = 'rejected';
self.reason = reason;
}
}
try{
executor(resolve,reject);
}catch(e){ //處理異常狀態,傳給reject
reject(e);
}
};
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'resolved'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
};
module.exports = Promise;
複製程式碼
首先先定義一個Promise函式,並且接受一個executor執行函式,將resolve和reject傳參傳進去,定義私有屬性status,value,reason。 Promise有三個狀態,status用來記錄他們: 初始狀態為pending 成功狀態為resolved 失敗狀態為rejected
然後使用prototype掛載一個then方法, 方法中要傳入一個成功的回掉和一個失敗的回掉, 如果成功就調取成功的回掉, 失敗就調取失敗的回掉
最後將函式匯出,就實現了一個最基礎功能的Promise。
但是這個Promise還是一個同步的方法,如果想在程式碼中使用非同步,比如:
let p=new Promise(function(resolve,reject){
setTimeout(function(){
resolve('成功');
},1000);
//throw new Error('錯誤');
});
複製程式碼
我們就需要將他變為非同步的:
function Promise(executor){
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
self.onResolvedCallbacks= []; //存放成功的回掉
self.onRejectedCallbacks= []; //存放失敗的回掉
function resolve(value){
if(self.status === 'pending'){
self.status = 'resolved';
self.value = value;
self.onResolvedCallbacks.forEach(function(fn){
fn();
});
}
}
function reject(reason){
if(self.status === 'pending'){
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function(fn){
fn();
});
}
}
try{
executor(resolve,reject);
}catch(e){ //處理異常狀態,傳給reject
reject(e);
}
}
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(function(){
onFulfilled(self.value);
});
self.onRejectedCallbacks.push(function(){
onRejected(self.reason);
});
}
};
module.exports = Promise;
複製程式碼
如果他是非同步的,我們就不能在then方法中用status的成功失敗狀態來判斷他走的那,因為then方法執行後有可能params中還沒執行resolve或者reject,那麼我們就在Promise例項上再新增onResolvedCallbacks和onRejectedCallbacks兩個陣列來存放他的回掉,如果執行的是成功,失敗就會存預設的undefined。在呼叫時用forEach迴圈陣列依次知性方法。 原生的Promise還可以then多次:
function Promise(executor){
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
self.onResolvedCallbacks= [];
self.onRejectedCallbacks= [];
function resolve(value){
self.status = 'resolved';
self.value = value;
self.onResolvedCallbacks.forEach(function(fn){
fn();
});
}
function reject(reason){
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function(fn){
fn();
});
}
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
};
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
let promise2; //實現鏈式操作
if(self.status === 'resolved'){
promise2 = new Promise(function(resolve, reject){
try{
let x = onFulfilled(self.value);
resolve(x);
}catch(e){
reject(e);
}
});
}
if(self.status === 'rejected'){
promise2 = new Promise(function(resolve, reject){
try{
let x = onRejected(self.reason);
reject(x);
}catch(e){
reject(e);
}
});
}
if(self.status === 'pending'){
promise2 = new Promise(function(resolve, reject){
self.onResolvedCallbacks.push(function(){
try{
let x = onFulfilled(self.value);
resolve(x);
}catch(e){
reject(e);
}
});
self.onRejectedCallbacks.push(function(){
try{
let x = onRejected(self.reason);
reject(x);
}catch(e){
reject(e);
}
});
});
}
return promise2;
}
module.exports = Promise;
複製程式碼
當然他then的鏈式呼叫不會有then屬性,所以我們可以判斷Promise每次then都會new一個新的Promise我們用Promise2來表示,then的時候new一個新的Promise並且return給下一個then。 then中無論是成功的回掉還是失敗的毀掉,只要返回了結果,就會走下一個then中的成功,發生錯誤才會走下一個then中的失敗,then中可以return普通值,也可return一個新的Promise,還有可能return 一個{then:xxx},當然更有promise.then().then.then(function(){});這種奇葩的用法
function Promise(executor){
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
self.onResolvedCallbacks= [];
self.onRejectedCallbacks= [];
function resolve(value){
self.status = 'resolved';
self.value = value;
self.onResolvedCallbacks.forEach(function(fn){
fn();
});
}
function reject(reason){
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function(fn){
fn();
});
}
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
};
function resolvePromise(p2,x,resolve,reject){
//1.處理亂寫
//2.判斷返回的是不是自己
if(p2 === x){
reject(new typeError('迴圈引用'));
}
//判斷x是不是params(判斷x是不是object)
let called; //表示是否呼叫過成功或者失敗
if(x !== null || typeof x === 'object' || typeof x === 'function'){
//判斷promise只要判斷物件中是否有then方法
try{
let then = x.then;
if(typeof then === 'function'){ //then返回的可能是{then:xxx},判斷then是不是一個函式
then.call(x,function(y){ //成功了以後可能會執行resolve(new Promise())用遞迴來解決
if(called) return;
called = true;
resolvePromise(p2,y,resolve,reject);
},function(err){
if(called) return;
called = true;
reject(err);
});
}else{
resolve(x);
}
}catch(e){
if(called) return;
called = true;
reject(e);
}
}else{ //esle普通值
resolve(x);
}
}
Promise.prototype.then = function(onFulfilled,onRejected){ //判斷onFulfilled是不是一個函式,不是給他個函式
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){
return value;
}
onRejected = typeof onRejected === 'function' ? onRejected : function(err){
throw err;
}
let self = this;
let promise2; //實現鏈式操作
if(self.status === 'resolved'){
promise2 = new Promise(function(resolve, reject){
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
});
}
if(self.status === 'rejected'){
promise2 = new Promise(function(resolve, reject){
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
});
}
if(self.status === 'pending'){
promise2 = new Promise(function(resolve, reject){
self.onResolvedCallbacks.push(function(){
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
});
self.onRejectedCallbacks.push(function(){
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
});
});
}
return promise2;
}
module.exports = Promise;
複製程式碼
我們就定義一個resolvePromise來處理then中的返回結果,如果返回的是個錯誤資訊,就用try{}catch(){}讓他走reject 最後的最後,Promise中可以非同步執行程式碼,then方法中應該也可以實現非同步,很簡單,只要在相應的位置加上setTimeout就ok了,記得不要忘了加上try{}catch(){}來過濾錯誤資訊並且傳到reject中
function Promise(executor){
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
self.onResolvedCallbacks= [];
self.onRejectedCallbacks= [];
function resolve(value){
self.status = 'resolved';
self.value = value;
self.onResolvedCallbacks.forEach(function(fn){
fn();
});
}
function reject(reason){
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function(fn){
fn();
});
}
try{
executor(resolve,reject);
}catch(e){
reject(e);
}
};
function resolvePromise(p2,x,resolve,reject){
//1.處理亂寫
//2.判斷返回的是不是自己
if(p2 === x){
reject(new typeError('迴圈引用'));
}
//判斷x是不是params(判斷x是不是object)
let called; //表示是否呼叫過成功或者失敗
if(x !== null || typeof x === 'object' || typeof x === 'function'){
//判斷promise只要判斷物件中是否有then方法
try{
let then = x.then;
if(typeof then === 'function'){ //then返回的可能是{then:xxx},判斷then是不是一個函式
then.call(x,function(y){ //成功了以後可能會執行resolve(new Promise())用遞迴來解決
if(called) return;
called = true;
resolvePromise(p2,y,resolve,reject);
},function(err){
if(called) return;
called = true;
reject(err);
});
}else{
resolve(x);
}
}catch(e){
if(called) return;
called = true;
reject(e);
}
}else{ //esle普通值
resolve(x);
}
}
Promise.prototype.then = function(onFulfilled,onRejected){ //判斷onFulfilled是不是一個函式,不是給他個函式
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function(value){
return value;
}
onRejected = typeof onRejected === 'function' ? onRejected : function(err){
throw err;
}
let self = this;
let promise2; //實現鏈式操作
if(self.status === 'resolved'){
promise2 = new Promise(function(resolve, reject){
setTimeout(function(){
try{
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
}
if(self.status === 'rejected'){
promise2 = new Promise(function(resolve, reject){
setTimeout(function(){
try{
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
}
if(self.status === 'pending'){
promise2 = new Promise(function(resolve, reject){
self.onResolvedCallbacks.push(function(){
setTimeout(function(){
try{
let x = onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
self.onRejectedCallbacks.push(function(){
setTimeout(function(){
try{
let x = onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
});
}
return promise2;
}
module.exports = Promise;
複製程式碼