- Promise對(duì)象有以下幾種狀態(tài):
- pending: 初始狀態(tài), 既不是 fulfilled 也不是 rejected.
- fulfilled: 成功的操作.
- rejected: 失敗的操作.
1).Promise的初步框架
function Promise(executor) {
let self = this; //緩存this卵惦,當(dāng)前promise的實(shí)例
self.status = 'pending'; //初始狀態(tài)
self.value = 'undefined';//默認(rèn)成功的值
self.reason = 'undefined';//默認(rèn)失敗的原因
function resolve(value) { //成功狀態(tài)
if (self.status === 'pending') {
self.status = 'resolved';
self.value = value;
}
}
function reject(reason) { //失敗狀態(tài)
if (self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
}
}
try{
//因?yàn)榇撕瘮?shù)執(zhí)行可能會(huì)異常贡羔,所以需要捕獲交煞,如果出錯(cuò)了,需要用錯(cuò)誤對(duì)象reject
executor(resolve, reject)
}catch(e){
reject(e); // 捕獲的時(shí)候發(fā)生異常,就直接失敗了
}
}
Promise.prototype.then = function (onFulfilled, onRjected) {
let self = this;
if (self.status === 'resloved') {
onFulfilled(self.value)
}
if (self.status === 'rejected') {
onRjected(self.reason)
}
}
2).promise實(shí)例可以多次then,當(dāng)成功后會(huì)將then中的成功方法按順序執(zhí)行咖刃,我們可以先將then中的成功的回調(diào)和失敗的回調(diào)存到數(shù)組內(nèi)吟策,當(dāng)成功時(shí)調(diào)用成功的數(shù)組即可棠绘。
function Promise(executor) {
let self = this;
self.status = 'pending';
self.value = 'undefined';
self.reason = 'undefined';
------------------------------------------------------------------------------
//此處為增加的代碼
self.onResolvedCallbacks = []; // 存放then成功的回調(diào)
self.onRejectedCallbacks = []; // 存放then失敗的回調(diào)
------------------------------------------------------------------------------
function resolve(value) { //成功狀態(tài)
if (self.status === 'pending') {
self.status = 'resolved';
self.value = value;
------------------------------------------------------------------------------
//此處為增加的代碼
self.onResolvedCallbacks.forEach(function (fn) {
fn();
});
------------------------------------------------------------------------------
}
}
function reject(reason) { //失敗狀態(tài)
if (self.status === 'pending') {
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, onRjected) {
let self = this;
if (self.status === 'resloved') {
onFulfilled(self.value)
}
if (self.status === 'rejected') {
onRjected(self.reason)
}
------------------------------------------------------------------------------
//此處為增加的代碼
if(self.status === 'pending'){
self.onResolvedCallbacks.push(function(){
onFulfilled(self.value)
})
self.onRejectedCallbacks.push(function(){
onRjected(self.reason)
})
}
------------------------------------------------------------------------------
}
3).鏈?zhǔn)秸{(diào)用 jquery,jquery能實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用靠的就是返回this,promise不能返回this,promise實(shí)現(xiàn)鏈?zhǔn)秸{(diào)用靠的是返回一個(gè)新的promise
function Promise(executor) {
let self = this;
self.status = 'pending';
self.value = 'undefined';
self.reason = 'undefined';
self.onResolvedCallbacks = []; // 存放then成功的回調(diào)
self.onRejectedCallbacks = []; // 存放then失敗的回調(diào)
function resolve(value) { //成功狀態(tài)
if (self.status === 'pending') {
self.status = 'resolved';
self.value = value;
self.onResolvedCallbacks.forEach(function (fn) {
fn();
});
}
}
function reject(reason) { //失敗狀態(tài)
if (self.status === 'pending') {
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, onRjected) {
------------------------------------------------------------------------------
//我們的代碼可以在then中什么都不傳promise中值的穿透(實(shí)際使用)
//如果成功和失敗默認(rèn)不傳翠语,給一個(gè)函數(shù)(規(guī)范規(guī)定)
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) {
// 當(dāng)成功或者失敗執(zhí)行時(shí)有異常那么返回的promise應(yīng)該處于失敗狀態(tài)
// x可能是一個(gè)promise 也有可能是一個(gè)普通的值
try {
let x = onFulfilled(self.value);
// x可能是別人promise叽躯,寫一個(gè)方法統(tǒng)一處理
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
------------------------------------------------------------------------------
}
if (self.status === 'rejected') {
------------------------------------------------------------------------------
//增加的代碼
promise2 = new Promise(function (resolve, reject) {
try {
let x = onRjected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
------------------------------------------------------------------------------
}
if (self.status === 'pending') {
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 = onRjected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
------------------------------------------------------------------------------
})
}
------------------------------------------------------------------------------
//增加的代碼
return promise2;
------------------------------------------------------------------------------
}
4).解析then中的結(jié)果
function resolvePromise(promise2, x, resolve, reject) {
// 有可能這里返回的x是別人的promise
// 盡可能允許其他亂寫
//返回的結(jié)果和promise是同一個(gè)那么永遠(yuǎn)不會(huì)成功和失敗
if (promise2 === x) { //這里應(yīng)該報(bào)一個(gè)類型錯(cuò)誤,有問題
return reject(new TypeError('循環(huán)引用了'))
}
// 看x是不是一個(gè)promise,promise應(yīng)該是一個(gè)對(duì)象
//有些人寫的promise可能會(huì)既調(diào)用成功 又調(diào)用失敗肌括,如果兩個(gè)都調(diào)用先 調(diào)用誰另一個(gè)就忽略掉
let called; // 表示是否調(diào)用過成功或者失敗
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 可能是promise {},看這個(gè)對(duì)象中是否有then方法险毁,如果有then我就認(rèn)為他是promise了
try { // {then:1}
let then = x.then;
if (typeof then === 'function') {
// 成功
then.call(x, function (y) {
if (called) return
called = true
// y可能還是一個(gè)promise,在去解析直到返回的是一個(gè)普通值
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 { // 說明是一個(gè)普通值1
resolve(x); // 表示成功了
}
}
如果then中無論是成功的回調(diào)還是失敗的回調(diào)只要返回了結(jié)果就會(huì)走下一個(gè)then中的成功们童,如果有錯(cuò)誤走下一個(gè)then的失敗
如果第一個(gè)promise返回一個(gè)普通值,會(huì)進(jìn)到下一次then的成功的回調(diào),如果第一個(gè)promise返回了一個(gè)promise,需要等待返回的promise執(zhí)行后的結(jié)果傳遞給下一次then中
6).捕獲錯(cuò)誤的方法
Promise.prototype.catch = function (callback) {
return this.then(null, callback)
}
7).Promise的靜態(tài)方法
- all:全部成功才算成功
Promise.all = function (promises) {
//promises是一個(gè)promise的數(shù)組
return new Promise(function (resolve, reject) {
let arr = []; //arr是最終返回值的結(jié)果
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)
}
})
}
- race:只要有一個(gè)promise成功了 就算成功鲸鹦。如果第一個(gè)失敗了就失敗了
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
}
})
}
- resolve:生成一個(gè)成功的promise
Promise.resolve = function(value){
return new Promise(function(resolve,reject){
resolve(value);
})
}
- reject:生成一個(gè)失敗的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
})
}
8).promise規(guī)范中要求慧库,所有的onFufiled和onRjected都需要異步執(zhí)行,setTimeout(在onFufiled和onRjected處添加setTimeout)
Promise.prototype.then = function (onFulfilled, onRjected) {
//成功和失敗默認(rèn)不穿給一個(gè)函數(shù)
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) {
// 當(dāng)成功或者失敗執(zhí)行時(shí)有異常那么返回的promise應(yīng)該處于失敗狀態(tài)
// x可能是一個(gè)promise 也有可能是一個(gè)普通的值
-------------------------------------------------------------------------------------------------
setTimeout(function () {
try {
let x = onFulfilled(self.value);
// x可能是別人promise,寫一個(gè)方法統(tǒng)一處理
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);
}
})
})
}
// 當(dāng)調(diào)用then時(shí)可能沒成功 也沒失敗
if (self.status === 'pending') {
promise2 = new Promise(function (resolve, reject) {
// 此時(shí)沒有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;
}
9).promise測(cè)試
下載一個(gè)Promise的測(cè)試庫,promises-aplus-tests
- npm install -g promises-aplus-tests
- promises-aplus-tests 文件名
測(cè)試需要添加的代碼
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd
}