Promise
出現解決了js中的回調地獄的問題,使代碼更簡潔,是ES6中的規範和重要特性。它的使用很簡單,但你知道它是怎麼樣實現的嗎~~
如今咱們就來看一下Promise到底是怎麼樣實現的😄javascript
Promise
。看一下Promise
是如何使用的java
const promise = new Promise((resolve, reject) => {
try {
resolve('123');
} catch(err) {
reject('error');
}
});
promise
.then((msg) => {
console.log(msg)
})
複製代碼
function
做爲參數,function
中有resolve
和reject
兩個方法。resolve
表明成功後返回的值,reject
表明拒絕返回的緣由根據Promise
的使用來建立一個叫MyPromise
的類git
/** * @params {function} callback 須要執行的業務方法 */
class MyPromise {
// 構造方法接收一個function
constructor(callback) {
callback(this.resolve, this.reject); // 調用此function
}
resolve = (value) => {} // callback中執行的resolve方法
reject = (reason) => {} // callback中執行的reject方法
}
// 測試
var test = new MyPromise((resolve, reject) => {
console.log('my promise is running!');
}) // 打印出 my promise is running!
複製代碼
如今咱們建立的類已經能夠執行傳入的方法了,可是它傳入的resolve
和reject
方法是有什麼用的呢?
咱們接着看Promise規範 github
Promise
有三種狀態 pending
(等待),fulfilled
(完成),rejected
(拒絕)。pending
時,Promise能夠變爲fulfilled
或rejected
狀態fulfilled
時,Promise不能改變其狀態;必須有值且不能改變rejected
時,Promise不能改變其狀態;必須有拒絕的緣由且不能改變根據Promise
規則,接着寫剛剛建立的類:面試
const stateArr = ['pending', 'fulfilled', 'rejected']; // 三種狀態
/** * @params {function} callback 須要執行的業務方法 */
class MyPromise {
constructor(callback) {
this.state = stateArr[0]; // 當前狀態
this.value = null; // 完成時的返回值
this.reason = null; // 失敗緣由
callback(this.resolve, this.reject); // 調用此function
}
// callback中執行的resolve方法
resolve = (value) => {
// 判斷狀態是否須要是pending
if (this.state === stateArr[0]) {
this.state = stateArr[1]; // 更新狀態爲 fulfilled
this.value = value; // 寫入最終的返回值
}
}
// callback中執行的reject方法
reject = (reason) => {
// 判斷狀態是否須要是pending
if (this.state === stateArr[0]) {
this.state = stateArr[2]; // 更新狀態爲 rejected
this.reason = reason; // 寫入拒絕的緣由
}
}
}
複製代碼
測試一下: 數組
能夠看到,調用resolve
後,狀態變爲
fulfilled,再調用
reject
時,狀態和值都不會改變,這樣符合Promise規範~~
咱們的MyPromise
寫到這裏,他已經能夠實現更新狀態和傳值了,可是它的值怎麼樣輸出給咱們的業務呢?
由Promise
的使用能夠看到,它是經過then
方法來輸出值的。then
是是一個必要的方法,看一下then
的規範:promise
then
方法去訪問他的當前或最終的值或緣由then
方法接收兩個參數 onFulilled
和onRejected
下面是關於onFulilled
和onRejected
的規範(部分)異步
onFulilled
和onRejected
二者都是一個可選的參數:
onFulilled
不是一個函數,它必須被忽視onRejected
不是一個函數,它必須被忽視onFulilled
是一個函數:
value
做爲第一個參數onRejected
是一個函數:
reason
做爲第一個參數onFulfilled
或onRejected
onFulfilled
和onRejected
必須是一個函數then
能夠在同一個promise中屢次被調用then
必須返回一個promise
根據then函數的規則,咱們來設計這個then方法函數
const stateArr = ['pending', 'fulfilled', 'rejected']; // 三種狀態
class MyPromise {
constructor(callback) {
this.state = stateArr[0]; // 當前狀態
this.value = null; // 完成時的返回值
this.reason = null; // 失敗緣由
callback(this.resolve, this.reject); // 調用此function
}
// callback中執行的resolve方法
resolve = (value) => {
// 判斷狀態是否須要是pending
if (this.state === stateArr[0]) {
this.state = stateArr[1]; // 更新狀態爲 fulfilled
this.value = value; // 寫入最終的返回值
}
}
// callback中執行的reject方法
reject = (reason) => {
// 判斷狀態是否須要是pending
if (this.state === stateArr[0]) {
this.state = stateArr[2]; // 更新狀態爲 rejected
this.reason = reason; // 寫入拒絕的緣由
}
}
// then方法
then = (onFulilled, onRejected) => {
// 判斷onFulilled 和 onRejected是不是一個函數,若是不是函數則忽略它
onFulilled = typeof onFulilled === 'function' ? onFulilled : (value) => value;
onRejected = typeof onRejected === 'function' ? onRejected : (reason) => reason;
// 若是狀態是fulfilled
if (this.state === stateArr[1]) {
// then返回的必須是一個promise
return new MyPromise((resolve, reject) => {
try {
const result = onFulilled(this.value); // 執行傳入的onFulilled方法
// 若是onFulilled返回的是一個Promise,則調用then方法
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err);
}
})
}
// 若是狀態是rejected
if (this.state === stateArr[2]) {
// then返回的必須是一個promise
return new MyPromise((resolve, reject) => {
try {
const result = onRejected(this.reason); // 執行傳入的onRejected方法
// 若是onRejected返回的是一個Promise,則調用then方法
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err);
}
})
}
}
}
複製代碼
測試一下:oop
成功返回:
失敗返回:
至此,咱們的MyPromise
的已經基本能夠運行了,可是如今有一個很嚴重的缺陷,若是遇到異步的請求時候,resolve
不能按上下文執行,這會致使then方法執行失敗例如
var test = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 2000)
})
.then(msg => {
console.log(msg);
return 456;
})
複製代碼
由於在調用then
方法的時候,promise
的狀態尚未改變,而咱們的then
方法尚未處理pending狀態的邏輯。 這致使執行異步方法的時候,then方法不會返回任何東西
好比,在上面的例子中,javscript已經把then
方法執行了,但setTimeout
中的方法還在eventloop
中等待執行。 這樣須要作的是:
then
中的方法保存起來,等待resolve
或reject
執行後再調用剛剛保存的then
中的方法then
方法會被執行,因此須要用一個數據來保存這些方法// 在constructor中新增兩個數組分別用於裝then中的resolve和reject方法
constructor(callback) {
this.resolveArr = [];
this.rejectArr = [];
}
// 修改resolve方法
resolve = (value) => {
// 判斷狀態是否須要是pending
if (this.state === stateArr[0]) {
this.state = stateArr[1]; // 更新狀態爲 fulfilled
this.value = value; // 寫入最終的返回值
this.resolveArr.forEach(fun => fun(value)) // 循環執行then已插入的resolve方法
}
}
// 修改reject方法
reject = (reason) => {
// 判斷狀態是否須要是pending
if (this.state === stateArr[0]) {
this.state = stateArr[1]; // 更新狀態爲 fulfilled
this.reason = reason; // 寫入最終的返回值
this.rejectArr.forEach(fun => fun(reason)) // 循環執行then已插入的reject方法
}
}
// then方法中須要添加捕捉pending狀態的邏輯
then = (onFulilled, onRejected) => {
// 若是狀態爲pending
if (this.state === stateArr[0]) {
return new Promise((resolve, reject) => {
// 插入成功時調用的函數
this.resolveArr.push((value) => {
try {
const result = onFulilled(value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err);
}
})
// 插入失敗時調用的函數
this.rejectArr.push((value) => {
try {
const result = onRejected(value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err)
}
})
})
}
}
複製代碼
寫好了,測試一下~
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 2000)
})
.then(msg => {
console.log(msg);
return new MyPromise((resolve, reject) => {
setTimeout(()=> {
resolve(456)
}, 2000);
})
})
.then(msg => {
console.log(msg);
})
複製代碼
根據Promise規範實現的Promise
大體已經完成啦,最後咱們把Promise中實現的方法也補一下
// 在MyPromise原型中實現
class MyPromise {
// 調用then中的reject
catch = (reject) => {
this.then(null, reject);
}
}
複製代碼
MyPromise.resolve = (value) => {
return new MyPromise((resolve, reject) => { resolve(value) });
}
複製代碼
MyPromise.resolve = (reason) => {
return new MyPromise((resolve, reject) => { reject(reason) });
}
複製代碼
all
,race
,finally(原型方法)
,其實都是根據Promise中的原型方法和Promise規則實現的,這裏就不一一列舉啦。須要瞭解的小夥伴能夠自行去看const stateArr = ['pending', 'fulfilled', 'rejected']; // 三種狀態
class MyPromise {
constructor(callback) {
this.state = stateArr[0]; // 當前狀態
this.value = null; // 完成時的返回值
this.reason = null; // 失敗緣由
this.resolveArr = [];
this.rejectArr = [];
callback(this.resolve, this.reject); // 調用此function
}
// callback中執行的resolve方法
resolve = (value) => {
// 判斷狀態是否須要是pending
if (this.state === stateArr[0]) {
this.state = stateArr[1]; // 更新狀態爲 fulfilled
this.value = value; // 寫入最終的返回值
this.resolveArr.forEach(fun => fun(value)) // 循環執行then已插入的resolve方法
}
}
// callback中執行的reject方法
reject = (reason) => {
// 判斷狀態是否須要是pending
if (this.state === stateArr[0]) {
this.state = stateArr[1]; // 更新狀態爲 fulfilled
this.reason = reason; // 寫入最終的返回值
this.rejectArr.forEach(fun => fun(reason)) // 循環執行then已插入的reject方法
}
}
// then方法
then = (onFulilled, onRejected) => {
// 判斷onFulilled 和 onRejected是不是一個函數,若是不是函數則忽略它
onFulilled = typeof onFulilled === 'function' ? onFulilled : (value) => value;
onRejected = typeof onRejected === 'function' ? onRejected : (reason) => reason;
// 若是狀態爲pending
if (this.state === stateArr[0]) {
return new MyPromise((resolve, reject) => {
// 插入成功時調用的函數
this.resolveArr.push((value) => {
try {
const result = onFulilled(value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err);
}
})
// 插入失敗時調用的函數
this.rejectArr.push((value) => {
try {
const result = onRejected(value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err)
}
})
})
}
// 若是狀態是fulfilled
if (this.state === stateArr[1]) {
// then返回的必須是一個promise
return new MyPromise((resolve, reject) => {
try {
const result = onFulilled(this.value); // 執行傳入的onFulilled方法
// 若是onFulilled返回的是一個Promise,則調用then方法
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err);
}
})
}
// 若是狀態是rejected
if (this.state === stateArr[2]) {
// then返回的必須是一個promise
return new MyPromise((resolve, reject) => {
try {
const result = onRejected(this.reason); // 執行傳入的onRejected方法
// 若是onRejected返回的是一個Promise,則調用then方法
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch(err) {
reject(err);
}
})
}
}
// 調用then中的reject
catch = (reject) => {
this.then(null, reject);
}
}
MyPromise.resolve = (value) => {
return new MyPromise((resolve, reject) => { resolve(value) });
}
MyPromise.resolve = (reason) => {
return new MyPromise((resolve, reject) => { reject(reason) });
}
複製代碼
此次咱們瞭解了promise是如何實現的:
從構造函數開始,到三種狀態的實現,最後實現then方法一步步根據Promise規則
來實現Promise。瞭解完之後就能夠在面試官面前手寫一個Promise啦!😄