寫在前面
本篇文章將會帶大家從分解promise入手,一步步實現一個promise。但閱讀之前需要比較熟練地瞭解瞭解用法,結合用法看文章可能更容易理解。
結構
先看一下簡單的用法。
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
})
})
.then(value => { ... }, reason => { ... })
.catch(error => { ... })
Promise的構造函數接收了一個回調,這個回調就是下面要講到的執行器,執行器的參數resolve, reject也是兩個函數,
負責改變promise實例的狀態和它的值,then函數中的回調在狀態改變後執行。
注意:不是then函數在狀態改變後執行,而是then中的回調函數在狀態改變後執行。then方法會將其中的回調放入執行隊列,promise的狀態改變後再將隊列中的函數一一執行。
如果要實現一個最簡單的promise類,內部結構都要包含什麼呢?
- 狀態:fulfiled、rejected、pending
- 值:promise的值
- 執行器:提供改變promise狀態的入口
- resolve和reject方法:前者將promise改變爲fulfiled,後者將其改變爲rejected。可以在執行器內根據實際業務來控制是resolve或reject
- then方法:接收兩個回調,onFulfilled, onRejected。分別在promise狀態變爲fulfiled或rejected後執行,這裏涉及到將回調註冊進兩個執
行隊列的操作,後文會講到
const PENDING = 'pending'
const FULFILLED = 'fulfiled'
const REJECTED = 'rejected'
class NewPromise {
constructor(handler) {
this.state = PENDING
this.value = undefined
this.successCallback = []
this.failureCallback = []
try {
handler(this.resolve.bind(this), this.reject.bind(this))
} catch (e) {
this.reject(e)
}
}
// resolve和reject方法
resolve(value) { ... }
reject(reason) { ... }
// then方法
then(onFulfilled, onRejected) { ... }
}
結構中的每個部分是如何實現的呢?
Promise的執行器
執行器是我們初始化promise時候傳入的回調,是我們操作promise的入口,所以執行器的實現不復雜,也就是將我們傳入的回調執行一下。
class NewPromise {
...
handler(resolve.bind(this), reject.bind(this))
...
}
實際上,執行器會接受兩個回調,resolve和reject。它們真正起到改變promise狀態的作用。
resolve和reject
實際上是兩個函數,所做的事情不復雜。
- 改變promise的狀態
- 將接收的值作爲promise的value
- 依次執行then中註冊的回調
const PENDING = 'pending'
const FULFILLED = 'fulfiled'
const REJECTED = 'rejected'
class NewPromise {
constructor(handler) {
this.state = PENDING
this.value = undefined
// 兩個隊列,後面會講到
this.successCallback = []
this.failureCallback = []
try {
// 執行器,由於resolve和reject中用到了this,這裏需要bind一下
handler(this.resolve.bind(this), this.reject.bind(this))
} catch (e) {
this.reject(e)
}
}
resolve(value) {
if (this.state !== PENDING) return
this.state = FULFILLED
this.value = value
// 用setTimeout模擬異步方式
setTimeout(() => {
this.successCallback.forEach(item => {
item(value)
})
})
}
reject(reason) {
if (this.state !== PENDING) return
this.state = REJECTED
this.value = reason
setTimeout(() => {
this.failureCallback.forEach(item => {
setTimeout(item(reason))
})
})
}
}
看一下它們的實現,改變狀態、賦值value,最重要的一點:循環執行then方法註冊到隊列中的回調。而規範中要求回調以異步方式執行,保證在執行所有的回調之前,所有回調已經通過then註冊完成,所以這裏用setTimeout模擬了一下。
then方法:
(翻譯整理自Promise/A+ 規範)
promise必須提供then方法來訪問這個promise當前或者最終的值。then方法有兩個參數:onFulfilled, onRejected,都是可選的。關於這兩個參數,這裏有幾個規則:
onFulfilled, onRejected都不是函數的時候,必須被忽略
實際上忽略也就是如果不是函數,默認給它賦值成函數,返回值爲then所屬的promise的值。這樣是做是爲了在then()函數未傳回調的時候,可以將promise的值傳遞下去。
promise(resolve => resolve('success'))
.then()
.then(function(value) {
console.log(value)
})
具體實現上,在它不是函數的時候可以給它賦值一個默認函數,也可以直接調用新返回的promise中的resolve或reject將值傳下去,來達到忽略的效果
onFulfilled是函數的時候
- 必須在當前的promise的狀態變爲fulfilled的時候被調用,promise被resolve的值也就是它的第一個參數
- 不能在fulfilled之前被調用
- 最多隻能被調用一次
onRejected是函數的時候
- 必須在當前的promise的狀態變爲rejected的時候被調用,promise被reject的值也就是它的第一個參數。不能在rejected之前被調用
- 最多隻能被調用一次
then可能會被調用多次
- 當promise狀態變爲fulfilled,所有onFulfilled將會按照最開始在then方法中註冊的順序去調用
- 當promise狀態變爲rejected,所有onRejected將會按照最開始在then方法中註冊的順序去調用
就像下邊這樣:
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('success'))
})
promise.then(res => {
console.log(res, '第一次');
})
promise.then(res => {
console.log(res, '第二次');
})
鑑於這種情況,需要在我們實現的promise內部維護兩個隊列,隊列中的元素是then方法內的回調函數(onFulfilled, onRejected),每調用一次then,就向隊列中push一個回調,它們會在promise狀態改變時被依次執行。
返回一個promise,便於鏈式調用
promise2 = promise1.then(onFulfilled, onRejected);
then返回的promise(也就是promise2)的狀態,取決於其回調函數(onFulfilled或onRejected)的返回值或者promise1的狀態,具體表現爲:
- onFulfilled或onRejected的返回值是一個值x,那麼promise2的狀態爲resolve,值爲x
- 如果onFulfilled或onRejected執行出錯,並拋出了錯誤對象e,那麼promise2的狀態爲rejected,值爲這個錯誤對象e
- 如果onFulfilled不是一個函數,但promise1狀態變爲fulfilled,那麼promise2狀態也爲fulfilled,值與promise1相同
- 如果onRejected不是一個函數,但promise1狀態變爲rejected,那麼promise2狀態也爲rejected,值與promise1相同(這個值是作爲promise2的reason)
實現
上面我們認識了then方法,結合定義和平時的用法可以猜測出我們自己實現的promise內的then方法需要做下邊幾件事:
-
返回一個新的promise實例
-
then所屬的Promise在pending狀態,將then的回調(onFulfilled, onRejected)分別放入執行隊列等待執行,而這兩個隊列內的函數只有在then所屬的promise狀態被改變的時候執行。保證了規範中的onFulfilled, onRejected的執行時機。
-
then所屬的Promise狀態不爲pending時,執行隊列中的回調開始依次執行,然後根據已經改變的狀態以及回調的返回值來決定新的promise的狀態
- 舉例來說:
const promise1 = new Promise((resolve, reject) =>{ ... }) const promise2 = promise1.then(value => { return 'success' }, reason => { return 'failed' })
假設promise1被resolve了,由於then中傳入了代表onFulfilled的回調並且返回值爲success,那麼promise2會被resolve,值爲success。
假設promise2被reject了,由於then中傳入了代表onRejected的回調並且返回值爲failed,那麼promise2會被reject,reason是failed
下面一步步來實現then方法,先上結構:
class NewPromise {
constructor(handler) {
this.state = PENDING
this.value = undefined
// 兩個隊列,存放onFulfiled 和 onRejected
this.successCallback = []
this.failureCallback = []
try {
handler(this.resolve.bind(this), this.reject.bind(this))
} catch (e) {
this.reject(e)
}
}
then(onFulfilled, onRejected) {
return new NewPromise((resolveNext, rejectNext) => {
// pengding狀態向隊列中註冊回調
if (state === PENDING) {
successCallback.push(onFulfilled)
failureCallback.push(onRejected)
}
// 要保證在當前promise狀態改變之後,再去通過resolveNext或者rejectNext改變新的promise的狀態
if (state === FULFILLED) {
resolveNext(value)
}
if (state === REJECTED) {
rejectNext(value)
}
})
}
}
上面的結構基本實現了then函數的大概邏輯,但是沒有實現根據onFulfilled, onRejected兩個回調的執行結果來決定新的promise的狀態的效果,
只是將他們分別放到了各自的執行隊列中去。
最終then返回的promise的狀態和onFulfilled, onRejected的執行結果有關。我根據規範和實際情況整理了一張圖:
然後讓我們用代碼來實現它(單以onFulfilled的執行情況舉例)
try {
// 正常情況
if (typeof onFulfilled !== 'function') {
// 不是函數,直接忽略,將then所屬的promise作爲then返回的promise的值resolve來做到值的傳遞
resolveNext(value)
} else {
// 獲取then函數回調的執行結果
const res = onFulfilled(value)
if (res instanceof NewPromise) {
// 當執行結果返回的是一個promise實例,等待這個promise狀態改變後再改變then返回的promise的狀態
res.then(resolveNext, rejectNext)
} else {
// 當返回值是普通值,將其作爲新promise的值resolve
resolveNext(res)
}
}
} catch (e) {
// 出現異常,新promise的狀態變爲rejected,reason就是錯誤對象
rejectNext(e)
}
整個這一部分,需要放入隊列中等待then所屬的promise狀態改變再執行,從而改變then返回的promise的狀態。所以,我們需要將這一塊包裝起來。整合起來就是:
class NewPromise {
constructor(handler) {
this.state = PENDING
this.value = undefined
// 兩個隊列,存放onFulfiled 和 onRejected
this.successCallback = []
this.failureCallback = []
try {
handler(this.resolve.bind(this), this.reject.bind(this))
} catch (e) {
this.reject(e)
}
}
then(onFulfilled, onRejected) {
const { state, value } = this
return new NewPromise((resolveNext, rejectNext) => {
const resolveNewPromise = value => {
try {
// 正常情況
if (typeof onFulfilled !== 'function') {
// 不是函數,直接忽略,將then所屬的promise作爲then返回的promise的值resolve來做到值的傳遞
resolveNext(value)
} else {
// 獲取then函數回調的執行結果
const res = onFulfilled(value)
if (res instanceof NewPromise) {
// 當執行結果返回的是一個promise實例,等待這個promise狀態改變後再改變then返回的promise的狀態
res.then(resolveNext, rejectNext)
} else {
// 當返回值是普通值,將其作爲新promise的值resolve
resolveNext(res)
}
}
} catch (e) {
// 出現異常,新promise的狀態變爲rejected,reason就是錯誤對象
rejectNext(e)
}
}
const rejectNewPromise = reason => {
try {
// 正常情況
if (typeof onRejected !== 'function') {
// 不是函數,直接忽略,將then所屬的promise作爲then返回的promise的值reject來做到值的傳遞
rejectNext(reason)
} else {
// 獲取then函數回調的執行結果
const res = onRejected(reason)
if (res instanceof NewPromise) {
// 當執行結果返回的是一個promise實例,等待這個promise狀態改變後再改變then返回的promise的狀態
res.then(resolveNext, rejectNext)
} else {
// 當返回值是普通值,將其作爲新promise的值reject
rejectNext(res)
}
}
} catch (e) {
// 出現異常,新promise的狀態變爲rejected,reason就是錯誤對象
rejectNext(e)
}
}
if (state === PENDING) {
this.successCallback.push(resolveNewPromise)
this.failureCallback.push(rejectNewPromise)
}
// 要保證在當前promise狀態改變之後,再去改變新的promise的狀態
if (state === FULFILLED) {
resolveNewPromise(value)
}
if (state === REJECTED) {
rejectNewPromise(value)
}
})
}
}
我們在自己的實現中是定義了兩個數組作爲任務隊列存放then註冊的回調,而實際的promise中,then方法是將回調註冊到微任務隊列中。等到promise狀態改變,執行微任務隊列中的任務。微任務在概念上可以認爲是異步任務,這也印證了規範中then的回調必須異步執行的說法。關於事件循環的一些知識點,我總結過一篇文章,今天,我明白了JS事件循環機制
catch函數
catch函數是用來處理異常的,當promise狀態變爲rejected的時候,捕獲到錯誤原因。那麼假設不用catch,也可以在then函數的第二個回調中捕獲這個錯誤。
而且catch返回的是一個promise,所以與調用Promise.prototype.then(undefined, onRejected)的行爲是一樣的
catch(onRejected) {
return this.then(undefined, onRejected)
}
resolve方法
Promise.resolve(value)返回的是一個promise對象,用於將傳入的值value包裝爲promise對象。
那這樣做有什麼意義呢?實際上value是一個不確定的值,可能是promise也可能不是,沒準可以調用then方法,也沒準不可以。但是可以通過resolve方法將行爲統一起來。
const promise = function() {
if (shouldBePromise) {
return new Promise(function(resolve, reject) {
resolve('ok')
})
}
return 'ok'
}
promise().then(() => {
...
})
promise返回的結果取決於shouldBePromise,假設shouldBePromise爲false,那麼promise就返回了字符串ok,下邊就不能調用then方法。
這個時候可以用Promise().resolve包起來,這樣promise返回的始終是一個promise實例,保證了then方法的順利調用。
Promise.resolve(promise()).then(() => {
...
})
總結一下特點:Promise.resolve的參數如果:
- 不傳,返回一個resolved狀態的Promise
- 是一個thenable對象(即帶有"then"方法),返回的Promise的狀態將在這個對象狀態改變時改變,並且與該對象的狀態保持一致
- 是普通值,返回一個resolved狀態的Promise,該promise的值爲這個普通值
- 是一個Promise對象,返回這個對象
static resolve(value) {
// value不存在,直接返回一個resolved狀態的promise
if (!value) {
return new NewPromise(function (resolve) {
resolve()
})
}
// value是promise實例,直接返回
// 在這裏需要首先判斷是否是promise實例,再進行下邊的判斷
// 因爲我們自己構造的promise也是是object,也有then方法
if (value instanceof NewPromise) {
return value
}
// 是thenable對象,返回的新的promise實例需要在value狀態改變後再改變,且狀態跟隨value的狀態
if (typeof value === 'object' && typeof value.then === 'function') {
return new NewPromise((resolve, reject) => {
value.then(resolve, reject)
})
}
// value是普通值,返回新的promise並resolve這個普通值
return new NewPromise(resolve => {
resolve(value)
})
}
reject方法
reject方法對比resolve相對簡單,它總是返回一個reject的promise對象,reject的原因是我們傳入的reason
static reject(reason) {
return new NewPromise((resolve, reject) => {
reject(reason)
})
}
finally方法
返回的是一個promise,作用是在promise結束時,無論結果是fulfilled或者是rejected,都會執行回調函數。返回的新promise的狀態和值取決於原來的promise。
finally(callback) {
// 返回值是promise對象,回調在then中執行,也就符合了promise結束後調用的原則
return this.then(
// then方法的onFulfiled 和 onRejected都會被傳入,保證無論resolved或rejected都會被執行
// 獲取到promise執行成功的結果,將這個結果作爲返回的新promise的值
res => NewPromise.resolve(callback())
.then(() => {
return res
}),
// 獲取執行失敗的結果。原理同上
error => NewPromise.resolve(callback())
.then(() => {
throw error
})
)
}
all方法
Promise.all(param) 接收一個參數數組,返回一個新的promise實例。當參數數組內的promise都resolve後或者參數內的實例執行完畢後,新返回的promise纔會resolve。
數組內任何一個promise失敗(rejected),新返回的promise失敗,失敗原因就是第一個失敗的promise的結果。
const p1 = Promise.resolve(1),
coint p2 = Promise.resolve(2),
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {
console.log(results); // [1, 2, 3]
});
由此可知,all方法需要返回一個新的promise實例,然後根據接收的參數數組執行情況,控制新的promise實例的狀態與值
static all(instanceList) {
return new NewPromise((resolve, reject) => {
// 定義存放結果的數組
const results = []
let count = 0
if (instanceList.length === 0) {
resolve(results)
return
}
instanceList.forEach((item, index) => {
// 由於實例列表中的每個元素可能是各種各樣的,所以要用this.resolve方法包裝一層
this.resolve(item).then(res => {
results[index] = res
count++
// 當都執行完,resolve新返回的promise
if (count === instanceList.length) {
resolve(results)
}
}, error => {
// 一旦有一個出錯,就reject新返回的promise
reject(error)
})
})
})
}
實現之後可以清楚的看到,all方法會並行執行所有promise,結果按傳入的promise數組的順序輸出。這讓我想起了以前面試碰到的一個題目:
併發所有請求,按順序輸出。可以用Promise.all實現。但實際上會有請求失敗的情況,所以更好的方式是下邊要講到的Promise.allSettled。
allSettled方法
如果說finally提供了在單個promise是否成功都需要執行代碼提供了一種方式,那麼allSettled就是爲多個promise是否成功的場景提供了同樣的操作方式。
Promise.allSettled()方法返回一個promise,該promise在所有給定的promise已被解析或被拒絕後解析,並且每個對象都描述每個promise的結果。
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];
Promise.allSettled(promises).
then((results) => results.forEach((result) => console.log(result.status)));
// expected output:
// "fulfilled"
// "rejected"
不同於Promise.all的一旦有一個執行失敗,就無法獲得所有promise都執行完成的時間點的特點。無論某個promise成功與否,一旦所有的promise都完成,就可以獲得這個時間點。因爲其返回的新的promise,總是被resolve的,並且值是所有promise執行結果的描述。
[
{"status":"rejected","reason":"失敗"},
{"status":"fulfiled","value":"成功"}
]
要實現它,需要在每個promise執行的時候把結果記錄下來放進一個數組內,最後在所有promise執行完成後,resolve結果數組,改變返回的新的promise的狀態。
static allSettled(instanceList) {
return new NewPromise((resolve, reject) => {
const results = []
let count = 0
if (instanceList.length === 0) {
resolve([])
return
}
// 定義一個函數,來生成結果數組
const generateResult = (result, i) => {
count++
results[i] = result
// 一旦全部執行完成,resolve新返回的promise
if (count === instanceList.length) {
resolve(results)
}
}
instanceList.forEach((item, index) => {
// 在每個promise完成後將狀態記錄到結果數組中
this.resolve(item).then(
value => {
generateResult({
status: FULFILLED,
value
}, index)
},
reason => {
generateResult({
status: REJECTED,
reason
}, index)
}
)
})
})
}
race方法
與all方法類似,接受一個實例數組爲參數,返回新的promise。但區別是一旦實例數組中的某個promise解決或拒絕,返回的promise就會解決或拒絕。
static race(instanceList) {
return new NewPromise((resolve, reject) => {
if (instanceList.length === 0) {
resolve([])
return
}
instanceList.forEach(item => {
// 由於實例列表中的每個元素可能是各種各樣的,所以要用this.resolve方法包裝一層
this.resolve(item).then(res => {
// 一旦有一個resolve了,那麼新返回的promise狀態就被resolve
resolve(res)
}, error => {
reject(error)
})
})
})
}
完整代碼
到此爲止就實現了一個相對完整的promise,代碼如下:
class NewPromise {
constructor(handler) {
this.state = PENDING
this.value = undefined
this.successCallback = []
this.failureCallback = []
try {
handler(this.resolve.bind(this), this.reject.bind(this))
} catch (e) {
// 執行器出現錯誤需要reject
this.reject(e)
}
}
resolve(value) {
if (this.state !== PENDING) return
this.state = FULFILLED
this.value = value
// 規範中要求then中註冊的回調以異步方式執行,保證在resolve執行所有的回調之前,
// 所有回調已經通過then註冊完成
setTimeout(() => {
this.successCallback.forEach(item => {
item(value)
})
})
}
reject(reason) {
if (this.state !== PENDING) return
this.state = REJECTED
this.value = reason
setTimeout(() => {
this.failureCallback.forEach(item => {
item(reason)
})
})
}
then(onFulfilled, onRejected) {
const { state, value } = this
return new NewPromise((resolveNext, rejectNext) => {
const resolveNewPromise = value => {
try {
// 正常情況
if (typeof onFulfilled !== 'function') {
// 不是函數,直接忽略,將then所屬的promise作爲then返回的promise的值resolve來做到值的傳遞
resolveNext(value)
} else {
// 獲取then函數回調的執行結果
const res = onFulfilled(value)
if (res instanceof NewPromise) {
// 當執行結果返回的是一個promise實例,等待這個promise狀態改變後再改變then返回的promise的狀態
res.then(resolveNext, rejectNext)
} else {
// 當返回值是普通值,將其作爲新promise的值resolve
resolveNext(res)
}
}
} catch (e) {
// 出現異常,新promise的狀態變爲rejected,reason就是錯誤對象
rejectNext(e)
}
}
const rejectNewPromise = reason => {
try {
// 正常情況
if (typeof onRejected !== 'function') {
// 不是函數,直接忽略,將then所屬的promise作爲then返回的promise的值reject來做到值的傳遞
rejectNext(reason)
} else {
// 獲取then函數回調的執行結果
const res = onRejected(reason)
if (res instanceof NewPromise) {
// 當執行結果返回的是一個promise實例,等待這個promise狀態改變後再改變then返回的promise的狀態
res.then(resolveNext, rejectNext)
} else {
// 當返回值是普通值,將其作爲新promise的值reject
rejectNext(res)
}
}
} catch (e) {
// 出現異常,新promise的狀態變爲rejected,reason就是錯誤對象
rejectNext(e)
}
}
if (state === PENDING) {
this.successCallback.push(resolveNewPromise)
this.failureCallback.push(rejectNewPromise)
}
// 要保證在當前promise狀態改變之後,再去改變新的promise的狀態
if (state === FULFILLED) {
resolveNewPromise(value)
}
if (state === REJECTED) {
rejectNewPromise(value)
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(callback) {
// 返回值是promise對象,回調在then中執行,也就符合了promise結束後調用的原則
return this.then(
// then方法的onFulfiled 和 onRejected都會被傳入,保證無論resolved或rejected都會被執行
// 獲取到promise執行成功的結果,將這個結果作爲finally返回的新的promise的值
res => NewPromise.resolve(callback())
.then(() => {
return res
}),
// 獲取執行失敗的結果。原理同上
error => NewPromise.resolve(callback())
.then(() => {
throw error
})
)
}
static allSettled(instanceList) {
return new NewPromise((resolve, reject) => {
const results = []
let count = 0
if (instanceList.length === 0) {
resolve([])
return
}
// 定義一個函數,來生成結果數組
const generateResult = (result, i) => {
count++
results[i] = result
// 一旦全部執行完成,resolve新返回的promise
if (count === instanceList.length) {
resolve(results)
}
}
instanceList.forEach((item, index) => {
// 在每個promise完成後將狀態記錄到結果數組中
this.resolve(item).then(
value => {
generateResult({
status: FULFILLED,
value
}, index)
},
reason => {
generateResult({
status: REJECTED,
reason
}, index)
}
)
})
})
}
static resolve(value) {
// value不存在,直接返回一個resolved狀態的promise
if (!value) {
return new NewPromise(function (resolve) {
resolve()
})
}
// value是promise實例,直接返回
// 在這裏需要首先判斷是否是promise實例,再進行下邊的判斷
// 因爲我們自己構造的promise也是是object,也有then方法
if (value instanceof NewPromise) {
return value
}
// 是thenable對象,返回的新的promise實例需要在value狀態改變後再改變,且狀態跟隨value的狀態
if (typeof value === 'object' && typeof value.then === 'function') {
return new NewPromise((resolve, reject) => {
value.then(resolve, reject)
})
}
// value是普通值,返回新的promise並resolve這個普通值
return new NewPromise(resolve => {
resolve(value)
})
}
static reject(reason) {
return new NewPromise((resolve, reject) => {
reject(reason)
})
}
static all(instanceList) {
return new NewPromise((resolve, reject) => {
// 定義存放結果的數組
const results = []
let count = 0
if (instanceList.length === 0) {
resolve(results)
return
}
instanceList.forEach((item, index) => {
// 由於實例列表中的每個元素可能是各種各樣的,所以要用this.resolve方法包裝一層
this.resolve(item).then(res => {
results[index] = res
count++
// 當都執行完,resolve新返回的promise
if (count === instanceList.length) {
resolve(results)
}
}, error => {
// 一旦有一個出錯,就reject新返回的promise
reject(error)
})
})
})
}
static race(instanceList) {
return new NewPromise((resolve, reject) => {
if (instanceList.length === 0) {
resolve([])
return
}
instanceList.forEach(item => {
// 由於實例列表中的每個元素可能是各種各樣的,所以要用this.resolve方法包裝一層
this.resolve(item).then(res => {
// 一旦有一個resolve了,那麼新返回的promise狀態就被resolve
resolve(res)
}, error => {
reject(error)
})
})
})
}
}
片尾廣告
想看我寫的更多技術文章可以關注公衆號:一口一個前端