function Promise(executor){
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
function resolve(value){
if( self.status === 'pending'){
self.status = 'fulfilled';
self.value = value;
}
}
function reject(reason){
if( self.status === 'pending'){
self.status = 'rejected';
self.reason = reason;
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'fulfilled'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
module.exports = Promise;
複製代碼
測試用例1數組
let Promise = require('Mypromise');
let promise = newPromise(function(resolve,reject){
resolve(results)
})
promise.then(function(data){
console.log(data);
},function(err){
console.log(err);
})
複製代碼
首先咱們定義一個status狀態變量,默認Promise處於pending狀態
promise
promise接收一個executor函數,該函數在構造promise實例時就執行,因此在Promise構造方法中執行executor,executor須要接收resolve做爲執行成功時的回調函數,接收reject做爲執行失敗時的回調函數,因此定義了resolve和reject方法
bash
resolve接收執行成功的返回結果做爲參數
reject 接收執行失敗的返回結果做爲參數
因此這裏定義了value表示成功結果,reason表示錯誤緣由
調用resolve或reject後,會讓promise進入filfilled成功狀態或rejected失敗狀態,而且只有promise爲在pending狀態下,才能切換到成功/失敗態
異步
promise實例須要用then方法註冊執行成功/失敗的回調方法,then中根據promise所處狀態,判斷調用成功仍是失敗的回調
這樣一個簡單的promise的實現就寫好了函數
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 = 'fulfilled';
self.value = value;
self.onResolvedCallbacks.forEach(function(fn){
fn();
})
}
}
function reject(reason){
if( self.status === 'pending'){//只能從pending狀態切換到rejected狀態
self.status = 'rejected';
self.reason = reason;
self.onRejectedCallbacks.forEach(function(fn){
fn();
})
}
}
executor(resolve,reject);
}
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
if(self.status === 'fulfilled'){
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;
複製代碼
測試用例2post
let promise = new Promise(function(resolve,reject){
http.get(url, function(results) {
resolve(results)
})
})
promise.then(function(data){
console.log('data',data);
},function(err){
console.log('err',err);
})
promise.then(function(data){
console.log('data',data);
},function(err){
console.log('err',err);
})
promise.then(function(data){
console.log('data',data);
},function(err){
console.log('err',err);
})
複製代碼
promise主要用於處理異步回調的狀況,上例中發起http請求,請求成功後,用resolve發起成功的回調;並調用屢次then註冊了多個成功、失敗的回調方法;若是執行成功,原生的promise會將每一個then的成功回調都執行一遍
測試
因爲異步的請求,當調用then時,promise還處於pending狀態,因此咱們須要將then註冊的回調方法暫存,以便成功或失敗時回調,爲此定義 onResolvedCallbacks 、onRejectedCallbacks 分別存放then註冊的成功、失敗回調方法,上例所示, 可能屢次調用then註冊,因此onResolvedCallbacks =[],是個數組
當執行成功會調用resolve,那咱們在實現resolve方法時,將全部then中的成功回調都調用一遍,就是這段代碼ui
self.onResolvedCallbacks.forEach(function(fn){
fn();
})
複製代碼
當執行異步操做時有可能發生異常,須要try/catch捕獲到異常,並使promise進入rejected狀態this
try {
executor(resolve,reject); //捕獲的時候發生異常,執行reject
} catch (error) {
reject(error)
}
複製代碼
能夠在executor中拋出throw new Error('error')測試
url
then中不管是執行成功的回調仍是失敗回調,只要有返回結果,都會走到下一個then(根據不一樣返回結果進入下一個then的不一樣回調,規則個人另外一偏文章juejin.im/post/5aae65…
promise是經過then中返回新的promise來實現鏈式調用的,試想:一個新的promise是能夠繼續調用then方法的,補充then方法以下
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
let promise2; //then返回的新Promise
if(self.status === 'fulfilled'){
//onFilfilled會同步執行,並返回新的promise2
promise2 = new Promise(function (resolve,reject) {
onFulfilled(self.value);
});
}
if(self.status === 'rejected'){
promise2 = new Promise(function (resolve,reject) {
onRejected(self.reason);
});
}
if(self.status === 'pending'){
promise2 = new Promise(function (resolve,reject) {
self.onResolvedCallbacks.push( function(){
//捕獲異步回調時的異常,若是有進入promise2的失敗態
try{
onFulfilled(self.value);
}catch (e){
reject(e);
}
});
self.onRejectedCallbacks.push( function(){
try{
onRejected(self.reason);
}catch (e){
reject(e);
}
});
});
}
return promise2;
}
複製代碼
上面代碼第一個if語句,執行成功回調時,返回新的promise2,由於new promise時,executor會當即執行,因此onFulfilled(成功回調)方法會同步執行,並捕獲其中的異常;第二個if語句失敗回調同理。
第三個if語句,若是是異步回調,執行promise2的executor方法時,只是將這個成功的回調onFulfilled加入成功回調隊列onResolvedCallbacks(失敗同理),當成功回調真正執行時,若是發生異常,還須要捕獲,並進入新promise2的失敗態
若是第一個promise返回一個普通值,會走到下一次then的成功的回調
若是第一個promise返回了一個promise,須要等待返回的promise執行後的結果,再傳遞給下一次then中。
因此咱們用x接收第一個then的返回值 let x = onFulfilled(self.value);
x多是普通值,也多是promise,也多是別人實現的promise, 這裏實現一個resolvePromise方法統一處理返回值
then的代碼更新以下 : 都用x接收回調函數的返回值,並調用resolvePromise來處理
Promise.prototype.then = function(onFulfilled,onRejected){
let self = this;
let promise2;//then返回的新Promise
if(self.status === 'fulfilled'){
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(){
try{
let x= onFulfilled(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch (e){
reject(e);
}
});
self.onRejectedCallbacks.push( function(){
try{
let x= onRejected(self.reason);
resolvePromise(promise2,x,resolve,reject);
}catch (e){
reject(e);
}
});
});
}
return promise2;
}
複製代碼
resolvePromise的實現以下
參數:
p2 :第二次then的promise實例
x:第一次then的返回值
resolve/reject : p2的 resolve/reject
function resolvePromise(p2,x,resolve,reject){
if(p2 === x){ //報一個類型錯誤
return reject(new TypeError('循環引用了'));
}
//判斷x是否是promise
if(x!== null || (typeof x === 'object'||typeof x === 'function')){
//x多是promise 看對象中是否有then方法,有then就認爲是promise
//取then方法有可能異常,發生異常就進入p2的失敗態
try {
let then = x.then;
if(typeof then === 'function'){
//認爲x是一個promise,馬上執行該promise的then方法
//若是x進入成功態,會觸發成功回調
then.call(x,function(y){
//y可能仍是一個promise,繼續解析,直到返回的是一個普通值
resolvePromise(p2,y,resolve,reject);
},function(err){ //若是x進入失敗態,會觸發p2的失敗態
reject(err);
});
}else{ //若是then不是方法,直接認爲返回一個對象,調用p2成功態
resolve(x);
}
} catch (error) {
reject(error);
}
}else{ //x是普通值,調用p2成功態
resolve(x);
}
};
複製代碼
若是有人把代碼寫成
let p1= new Promise(function (resolve,reject) {
resolve('success');
reject('fail1');
});
複製代碼
promise的處理方式是,一旦進入成功態,就成功了,不會再調用reject,反之亦然
這裏經過在resolvePromise方法中,加入called 標識,表示已經進入一個resolve或reject;若果called爲true,直接返回,若是爲false,置爲true
function resolvePromise(p2, x, resolve, reject) {
if (p2 === x) { //這裏應該報一個類型錯誤,有問題
return reject(new TypeError('循環引用了'))
}
let called; // 表示是否調用過成功或者失敗
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, function (y) {
if (called) return;
called = true;
resolvePromise(promise2, 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 { // 說明是一個普通值1
resolve(x); // 表示成功了
}
}
複製代碼
咱們能夠在then中什麼都不寫
p1.then().then().then(function(data){
console.log('data',data);
},function(err){
console.log('err',err);
})
複製代碼
p1的執行結果依然會穿透到最後一個then的相應的回調
這須要在then方法中一開始就判斷,是否有resolve/reject方法,若是沒有,須要給默認的處理方法
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled :
function(value){ //默認的成功回調,返回一個值,就會進入下一個then的成功回調
return value;
};
onRejected = typeof onRejected === 'function' ? onRejected :
function(err){//默認的失敗回調,拋出異常,就會進入下一個then的失敗回調
throw err;
};
複製代碼
捕獲錯誤的方法,catch就至關於一個then調用錯誤方法
Promise.prototype.catch = function (callback) {
return this.then(null,callback);
}
複製代碼
all接收一個成員爲promise實例的數組,依次執行,並按順序返回執行結果
當全部promise都執行成功,就進入成功態,有一個執行失敗了,就進入失敗態
//promises是一個promise的數組
Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
let arr = []; //arr是最終返回值的結果
let count = 0; // 表示成功了多少次
function processData(index, y) {
arr[index] = y;
if (++count === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(function (y) {
processData(i, y)
}, reject) //有一個失敗,就調用失敗回調
}
})
};
複製代碼
參數同all,只要有一個promise成功了,就算成功。若是有一個失敗了,就失敗了,其餘promise繼續執行
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
}
})
};
複製代碼
Promise.resolve 能夠理解爲 生成一個成功的promise
Promise.resolve = function(value){
return new Promise(function(resolve,reject){
resolve(value);
})
}
複製代碼
Promise.reject 即生成一個失敗的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
})
}
複製代碼
這裏用setTimeout模擬異步執行,將全部成功和失敗的回調都用setTimeout包裝,既然異步執行,還需捕獲異常
function Promise(executor) { // executor是一個執行函數
let self = this;
self.status = 'pending';
self.value = undefined; // 默認成功的值
self.reason = undefined; // 默認失敗的緣由
self.onResolvedCallbacks = []; // 存放then成功的回調
self.onRejectedCallbacks = []; // 存放then失敗的回調
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(e);
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 有可能這裏返回的x是別人的promise
// 儘量容許其餘亂寫
if (promise2 === x) { //這裏應該報一個類型錯誤,有問題
return reject(new TypeError('循環引用了'))
}
// 看x是否是一個promise,promise應該是一個對象
let called; // 表示是否調用過成功或者失敗
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 多是promise {},看這個對象中是否有then方法,若是有then我就認爲他是promise了
try { // {then:1}
let then = x.then;
if (typeof then === 'function') {
// 成功
then.call(x, function (y) {
if (called) return
called = true
// y可能仍是一個promise,在去解析直到返回的是一個普通值
resolvePromise(promise2, 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 { // 說明是一個普通值1
resolve(x); // 表示成功了
}
}
Promise.prototype.then = function (onFulfilled, onRjected) {
//成功和失敗默認不穿給一個函數
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
return value;
}
onRjected = typeof onRjected === 'function' ? onRjected : function (err) {
throw err;
}
let self = this;
let promise2; //返回的promise
if (self.status === 'resolved') {
promise2 = new Promise(function (resolve, reject) {
// 當成功或者失敗執行時有異常那麼返回的promise應該處於失敗狀態
// x多是一個promise 也有多是一個普通的值
setTimeout(function () {
try {
let x = onFulfilled(self.value);
// x多是別人promise,寫一個方法統一處理
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
if (self.status === 'rejected') {
promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
let x = onRjected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
// 當調用then時可能沒成功 也沒失敗
if (self.status === 'pending') {
promise2 = new Promise(function (resolve, reject) {
// 此時沒有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 = onRjected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
})
}
return promise2;
}
// 捕獲錯誤的方法
Promise.prototype.catch = function (callback) {
return this.then(null, callback)
}
// 解析所有方法
Promise.all = function (promises) {
//promises是一個promise的數組
return new Promise(function (resolve, reject) {
let arr = []; //arr是最終返回值的結果
let i = 0; // 表示成功了多少次
function processData(index, y) {
arr[index] = y;
if (++i === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(function (y) {
processData(i, y)
}, reject)
}
})
};
// 只要有一個promise成功了 就算成功。若是第一個失敗了就失敗了
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
}
})
}
// 生成一個成功的promise
Promise.resolve = function(value){
return new Promise(function(resolve,reject){
resolve(value);
})
}
// 生成一個失敗的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
})
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd
}
module.exports = Promise;
複製代碼