Promise做爲面試中的經典考題,咱們必定要深入學習和理解它! Promise有什麼用呢?答:咱們拿它解決異步回調問題。面試
異步回調的一個很大的問題在於callback hell也就是「回調地獄」。多層嵌套回調函數,嚴重影響代碼規範。Promise其實是把回調函數從doSomething函數中提取到了後面的then()方法裏,從而防止多重嵌套。一個Promise對象表示目前還不可用可是將來某個節點能夠被解析的值,這個值要麼被解析成功,要麼失敗拋出異常。它容許咱們以同步的方式編寫異步代碼。數組
Promise的構造函數用來構造一個Promise對象,其中入參匿名函數中resolve和reject這兩個也都是函數。若是resolve執行了,則出發Promise.then中成功的回調函數,若是reject執行了,則觸發了promise.then中拒絕的回調函數。promise
一個Promise對象一開始的值是pending準備狀態,執行了resolve()後,Promise對象的狀態值變爲onFulfilled,執行了reject()後,狀態值變爲onRejected。Promise對象的狀態值一旦肯定,就不會再改變。bash
promise有兩種異常捕獲方式,一個是then中的reject,另外一個是catch()方法。異步
沒法捕獲當前then中拋出的異常函數
var promise = Promise.resolve();
promise.then(()=>{
throw new Error("BOOM!");
}).then((success)=>{
console.log(success);
}, (error)=>{
console.log(error);
});
複製代碼
catch不只能捕獲then中拋出的異常,還能捕獲前面promise拋出的異常,因此建議使用catch方法。學習
var promise = Promise.reject("Boom!");
promise.then(()=>{
return "success";
}).then((success) => {
console.log(success);
throw new Error("Another Boom!");
}).catch((error) => {
console.log(error); //BOOM!
});
複製代碼
首先來看基礎版的代碼,能夠實現簡單的同步代碼,這一步是必需要可以寫出來的。ui
// 首先要明確Promise是一個類,因此咱們用class聲明。
// 其次,構造函數中接收一個executor,它有兩個參數,一個是resolve,一個是reject
// 這裏要注意,resolve和reject都是函數
class Promise(){
// 構造函數(入參是執行器,包括resolve和reject兩個函數)
constructor(executor){
// 必要的初始化,這裏用到狀態,值和緣由三個變量
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// 定義成功函數,入參是value
let resolve = value => {
// 首先要判斷state是否爲等待態,若是不是則不作任何處理
if(this.state === 'pending'){
// 修改狀態
this.state = 'fulfilled';
// 更新值
this.value = value;
}
};
// 定義失敗函數,入參是失敗緣由
let reject = reason => {
// 一樣的邏輯
if(this.state === 'pending'){
this.state = 'rejected';
this.reason = reason;
}
};
// 這是promise對象的的主邏輯,執行executor,若是執行器出錯,則捕獲錯誤後執行reject函數
try{
executor(resolve, reject);
}catch(err){
reject(err);
}
}
// 定義Promise的then函數
// then方法接收兩個參數,若是狀態爲fulfilled,執行onFulfilled
// 若是狀態爲rejected,則執行onRejected
then(onFulfilled, onRejected){
if(this.state === 'fulfilled'){
onFulfilled(this.value);
};
if(this.state === 'rejected'){
onRejected(this.reason);
};
}
}
複製代碼
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// 成功回調函數數組和失敗回調函數數組
this.onResolveCallbacks = [];
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){
if(this.state === 'fulfilled'){
onFulfilled(this.value);
}
if(this.state === 'rejected'){
onRejected(this.reason);
}
// 當狀態爲等待態時,咱們要將成功/失敗的回調函數加入到對應的數組中
if(this.state === 'pending'){
// onFulfilled傳入到成功數組
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected傳入到成功數組
this.onRejectedCallbacks.push(()=>{
onRejeced(this.reason);
})
}
}
}
}
複製代碼
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){
let promise2 = new Promise((resolve,reject) => {
if(this.state === 'fulfilled'){
let x = onFulfilled(this.value);
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);
})
};
});
return promise2;
}
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);
}
}
}
複製代碼