咱們工做中免不了運用promise用來解決異步回調問題。平時用的不少庫或者插件都運用了promise 例如axios、fetch等等。可是你知道promise是咋寫出來的呢?javascript
別怕~這裏有本promisesA+規範,便宜點10元賣給你了。 java
首先呢,promise確定是一個類,咱們就用class來聲明。ios
new Promise((resolve, reject)=>{})
,因此傳入一個參數(函數),祕籍裏叫他executor,傳入就執行。class Promise{
// 構造器
constructor(executor){
// 成功
let resolve = () => { };
// 失敗
let reject = () => { };
// 當即執行
executor(resolve, reject);
}
}
複製代碼
Promise存在三個狀態(state)pending、fulfilled、rejectednpm
pending(等待態)爲初始態,並能夠轉化爲fulfilled(成功態)和rejected(失敗態)axios
成功時,不可轉爲其餘狀態,且必須有一個不可改變的值(value)數組
失敗時,不可轉爲其餘狀態,且必須有一個不可改變的緣由(reason)promise
new Promise((resolve, reject)=>{resolve(value)})
resolve爲成功,接收參數value,狀態改變爲fulfilled,不可再次改變。異步
new Promise((resolve, reject)=>{reject(reason)})
reject爲失敗,接收參數reason,狀態改變爲rejected,不可再次改變。函數
如果executor函數報錯 直接執行reject();測試
因而乎,咱們得到如下代碼
class Promise{
constructor(executor){
// 初始化state爲等待態
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失敗的緣由
this.reason = undefined;
let resolve = value => {
// state改變,resolve調用就會失敗
if (this.state === 'pending') {
// resolve調用後,state轉化爲成功態
this.state = 'fulfilled';
// 儲存成功的值
this.value = value;
}
};
let reject = reason => {
// state改變,reject調用就會失敗
if (this.state === 'pending') {
// reject調用後,state轉化爲失敗態
this.state = 'rejected';
// 儲存失敗的緣由
this.reason = reason;
}
};
// 若是executor執行報錯,直接執行reject
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
複製代碼
class Promise{
constructor(executor){...}
// then 方法 有兩個參數onFulfilled onRejected
then(onFulfilled,onRejected) {
// 狀態爲fulfilled,執行onFulfilled,傳入成功的值
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
// 狀態爲rejected,執行onRejected,傳入失敗的緣由
if (this.state === 'rejected') {
onRejected(this.reason);
};
}
}
複製代碼
這下武學初成,能夠對付對付江湖小雜毛了,可是對於帶setTimeout的江洋大盜仍是沒轍。
如今基本能夠實現簡單的同步代碼,可是當resolve在setTomeout內執行,then時state仍是pending等待狀態 咱們就須要在then調用的時候,將成功和失敗存到各自的數組,一旦reject或者resolve,就調用它們
相似於發佈訂閱,先將then裏面的兩個函數儲存起來,因爲一個promise能夠有多個then,因此存在同一個數組內。
// 多個then的狀況
let p = new Promise();
p.then();
p.then();
複製代碼
成功或者失敗時,forEach調用它們
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// 成功存放的數組
this.onResolvedCallbacks = [];
// 失敗存放法數組
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 一旦resolve執行,調用成功數組的函數
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 一旦reject執行,調用失敗數組的函數
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
};
if (this.state === 'rejected') {
onRejected(this.reason);
};
// 當狀態state爲pending時
if (this.state === 'pending') {
// onFulfilled傳入到成功數組
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected傳入到失敗數組
this.onRejectedCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
}
複製代碼
我門經常用到new Promise().then().then()
,這就是鏈式調用,用來解決回調地獄
一、爲了達成鏈式,咱們默認在第一個then裏返回一個promise。祕籍規定了一種方法,就是在then裏面返回一個新的promise,稱爲promise2:promise2 = new Promise((resolve, reject)=>{})
二、當咱們在第一個then中return
了一個參數(參數未知,需判斷)。這個return出來的新的promise就是onFulfilled()或onRejected()的值
祕籍則規定onFulfilled()或onRejected()的值,即第一個then返回的值,叫作x,判斷x的函數叫作resolvePromise
return
的對象)、resolve、rejectclass Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
// 聲明返回的promise2
let promise2 = new Promise((resolve, reject)=>{
if (this.state === 'fulfilled') {
let x = onFulfilled(this.value);
// resolvePromise函數,處理本身return的promise和默認的promise2的關係
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'rejected') {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(()=>{
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.onRejectedCallbacks.push(()=>{
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
})
}
});
// 返回promise,完成鏈式
return promise2;
}
}
複製代碼
祕籍規定了一段代碼,讓不一樣的promise代碼互相套用,叫作resolvePromise
let p = new Promise(resolve => {
resolve(0);
});
var p2 = p.then(data => {
// 循環引用,本身等待本身完成,一生完不成
return p2;
})
複製代碼
一、判斷x
let then = x.then
二、當x是對象或者函數(默認promise)function resolvePromise(promise2, x, resolve, reject){
// 循環引用報錯
if(x === promise2){
// reject報錯
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 防止屢次調用
let called;
// x不是null 且x是對象或者函數
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+規定,聲明then = x的then方法
let then = x.then;
// 若是then是函數,就默認是promise了
if (typeof then === 'function') {
// 就讓then執行 第一個參數是this 後面是成功的回調 和 失敗的回調
then.call(x, y => {
// 成功和失敗只能調用一個
if (called) return;
called = true;
// resolve的結果依舊是promise 那就繼續解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失敗只能調用一個
if (called) return;
called = true;
reject(err);// 失敗了就失敗了
})
} else {
resolve(x); // 直接成功便可
}
} catch (e) {
// 也屬於失敗
if (called) return;
called = true;
// 取then出錯了那就不要在繼續執行了
reject(e);
}
} else {
resolve(x);
}
}
複製代碼
一、祕籍規定onFulfilled,onRejected都是可選參數,若是他們不是函數,必須被忽略
value => value
reason => throw err
二、祕籍規定onFulfilled或onRejected不能同步被調用,必須異步調用。咱們就用setTimeout解決異步問題class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
// onFulfilled若是不是函數,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected若是不是函數,就忽略onRejected,直接扔出錯誤
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 異步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
// 異步
setTimeout(() => {
// 若是報錯
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
// 異步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
// 異步
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
// 返回promise,完成鏈式
return promise2;
}
}
複製代碼
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
return promise2;
}
catch(fn){
return this.then(null,fn);
}
}
function resolvePromise(promise2, x, resolve, reject){
if(x === promise2){
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
if(called)return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, err => {
if(called)return;
called = true;
reject(err);
})
} else {
resolve(x);
}
} catch (e) {
if(called)return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
//resolve方法
Promise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
});
}
//reject方法
Promise.reject = function(val){
return new Promise((resolve,reject)=>{
reject(val)
});
}
//race方法
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject)
};
})
}
//all方法(獲取全部的promise,都執行then,把結果放到數組,一塊兒返回)
Promise.all = function(promises){
let arr = [];
let i = 0;
function processData(index,data){
arr[index] = data;
i++;
if(i == promises.length){
resolve(arr);
};
};
return new Promise((resolve,reject)=>{
for(let i=0;i<promises.length;i++){
promises[i].then(data=>{
processData(i,data);
},reject);
};
});
}
複製代碼
一、先在後面加上下述代碼
二、npm 有一個promises-aplus-tests插件 npm i promises-aplus-tests -g 能夠全局安裝 mac用戶最前面加上sudo
三、命令行 promises-aplus-tests [js文件名] 便可驗證
// 目前是經過他測試 他會測試一個對象
// 語法糖
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise;
//npm install promises-aplus-tests 用來測試本身的promise 符不符合promisesA+規範
複製代碼