在現代JavaScript開發中,Promise
對象已經成為了處理異步操作的標準工具。它提供了一種更加優雅和可讀的方式來處理異步代碼,避免了傳統的回調地獄(Callback Hell)問題。雖然JavaScript原生支持Promise
,但理解其內部實現機制對于深入掌握異步編程至關重要。本文將帶領你一步步實現一個簡易的Promise
對象,幫助你更好地理解其工作原理。
在開始實現之前,我們先回顧一下Promise
的基本概念。
Promise
是一個表示異步操作最終完成或失敗的對象。它有三種狀態:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
promise.then((value) => {
console.log(value); // 輸出: Success!
}).catch((error) => {
console.error(error);
});
在上面的例子中,Promise
在1秒后成功完成,并調用then
方法中的回調函數。
接下來,我們將一步步實現一個簡易的Promise
對象。我們將從最基本的Promise
構造函數開始,逐步添加then
、catch
等方法。
首先,我們需要定義一個Promise
構造函數。這個構造函數接受一個執行器函數(executor),該函數有兩個參數:resolve
和reject
。
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 初始狀態為pending
this.value = undefined; // 存儲成功的結果
this.reason = undefined; // 存儲失敗的原因
this.onFulfilledCallbacks = []; // 存儲成功的回調函數
this.onRejectedCallbacks = []; // 存儲失敗的回調函數
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback(this.value));
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback(this.reason));
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
}
在這個構造函數中,我們定義了resolve
和reject
函數,并在執行器函數中調用它們。我們還維護了一個狀態機,確保Promise
的狀態只能從pending
變為fulfilled
或rejected
。
then
方法then
方法是Promise
的核心方法之一,它用于注冊Promise
成功或失敗時的回調函數。
class MyPromise {
// ... 之前的代碼
then(onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value);
} else if (this.state === 'rejected') {
onRejected(this.reason);
} else {
this.onFulfilledCallbacks.push(onFulfilled);
this.onRejectedCallbacks.push(onRejected);
}
}
}
在這個實現中,如果Promise
已經完成或失敗,我們直接調用相應的回調函數。否則,我們將回調函數存儲在數組中,等待Promise
狀態改變時調用。
catch
方法catch
方法用于處理Promise
失敗的情況,它實際上是then
方法的一個特例。
class MyPromise {
// ... 之前的代碼
catch(onRejected) {
return this.then(null, onRejected);
}
}
catch
方法只是簡單地調用了then
方法,并傳入null
作為onFulfilled
回調。
Promise
的一個重要特性是支持鏈式調用。為了實現這一點,我們需要讓then
方法返回一個新的Promise
對象。
class MyPromise {
// ... 之前的代碼
then(onFulfilled, onRejected) {
const newPromise = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (error) {
reject(error);
}
} else if (this.state === 'rejected') {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (error) {
reject(error);
}
} else {
this.onFulfilledCallbacks.push((value) => {
try {
const result = onFulfilled(value);
resolve(result);
} catch (error) {
reject(error);
}
});
this.onRejectedCallbacks.push((reason) => {
try {
const result = onRejected(reason);
resolve(result);
} catch (error) {
reject(error);
}
});
}
});
return newPromise;
}
}
在這個實現中,then
方法返回一個新的Promise
對象。當原Promise
完成或失敗時,我們調用相應的回調函數,并將結果傳遞給新的Promise
。
我們的Promise
實現目前還不支持異步操作。為了支持異步操作,我們需要確保then
方法中的回調函數在Promise
狀態改變時被調用。
class MyPromise {
// ... 之前的代碼
then(onFulfilled, onRejected) {
const newPromise = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const result = onFulfilled(this.value);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const result = onRejected(this.reason);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
} else {
this.onFulfilledCallbacks.push((value) => {
setTimeout(() => {
try {
const result = onFulfilled(value);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push((reason) => {
setTimeout(() => {
try {
const result = onRejected(reason);
resolve(result);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return newPromise;
}
}
在這個實現中,我們使用setTimeout
將回調函數的執行推遲到下一個事件循環中,從而確保異步操作的正確執行。
Promise.resolve
和Promise.reject
Promise.resolve
和Promise.reject
是Promise
類的靜態方法,用于快速創建一個已解決或已拒絕的Promise
。
class MyPromise {
// ... 之前的代碼
static resolve(value) {
return new MyPromise((resolve) => {
resolve(value);
});
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
}
Promise.all
Promise.all
方法用于將多個Promise
實例包裝成一個新的Promise
實例,只有當所有Promise
都成功時,新的Promise
才會成功。
class MyPromise {
// ... 之前的代碼
static all(promises) {
return new MyPromise((resolve, reject) => {
const results = [];
let completedCount = 0;
promises.forEach((promise, index) => {
promise.then((value) => {
results[index] = value;
completedCount++;
if (completedCount === promises.length) {
resolve(results);
}
}).catch((error) => {
reject(error);
});
});
});
}
}
在這個實現中,我們遍歷所有的Promise
實例,并在每個Promise
成功時將其結果存儲在results
數組中。當所有Promise
都成功時,我們調用resolve
方法。
Promise.race
Promise.race
方法用于將多個Promise
實例包裝成一個新的Promise
實例,新的Promise
的狀態由最先完成的Promise
決定。
class MyPromise {
// ... 之前的代碼
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
promise.then((value) => {
resolve(value);
}).catch((error) => {
reject(error);
});
});
});
}
}
在這個實現中,我們遍歷所有的Promise
實例,并在第一個Promise
完成時調用resolve
或reject
方法。
現在,我們已經實現了一個簡易的Promise
對象。讓我們通過一些測試用例來驗證它的正確性。
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('Success!');
}, 1000);
});
promise.then((value) => {
console.log(value); // 輸出: Success!
}).catch((error) => {
console.error(error);
});
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000);
});
promise.then((value) => {
console.log(value); // 輸出: 1
return value + 1;
}).then((value) => {
console.log(value); // 輸出: 2
}).catch((error) => {
console.error(error);
});
Promise.all
測試const promise1 = MyPromise.resolve(1);
const promise2 = MyPromise.resolve(2);
const promise3 = MyPromise.resolve(3);
MyPromise.all([promise1, promise2, promise3]).then((values) => {
console.log(values); // 輸出: [1, 2, 3]
}).catch((error) => {
console.error(error);
});
Promise.race
測試const promise1 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 1');
}, 500);
});
const promise2 = new MyPromise((resolve) => {
setTimeout(() => {
resolve('Promise 2');
}, 1000);
});
MyPromise.race([promise1, promise2]).then((value) => {
console.log(value); // 輸出: Promise 1
}).catch((error) => {
console.error(error);
});
通過本文,我們一步步實現了一個簡易的Promise
對象。雖然這個實現并不完整,但它涵蓋了Promise
的核心功能,包括狀態管理、鏈式調用、異步操作處理等。通過這個實現,我們不僅加深了對Promise
的理解,還為后續學習更復雜的異步編程模式打下了堅實的基礎。
在實際開發中,JavaScript原生的Promise
對象已經非常成熟和強大,建議直接使用原生Promise
。但對于想要深入理解Promise
內部機制的開發者來說,手動實現一個簡易的Promise
是一個非常有益的練習。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。