什么是Promise (含如何判斷一個值是Promise)
本文旨在對 Promise 的規(guī)范進行解釋, 便于讀者在學(xué)習(xí) Promise 的過程中梳理 Promise 之間的操作關(guān)系, 不對具體的代碼實現(xiàn)和Promise用法進行解釋.
比如, 為什么 [MDN-await] 中要提及一個 thenable 對象, 而且這個 thenable 對象還可以和 Promise 實例一樣使用
await
等待處理, 這就涉及到了下面的內(nèi)容.
由于筆者編程水平的限制, 不可避免存在錯漏或者語意不清的地方.
Promise A+ 規(guī)范
參考資料: [Promises/A+]
在 ES6 之前,社區(qū)已經(jīng)有了 Promise A+ 規(guī)范, 該規(guī)范定義了 Promise 的行為和接口. 根據(jù)規(guī)范, 任何具有 .then()
方法的函數(shù)或?qū)ο蠖伎梢员徽J為是一個 Promise ,并且可以進行 Promise 之間的操作。
這個具有 .then()
方法的函數(shù)/對象被稱為 thenable 對象, 你可以在 [MDN-Promise#thenable] 和 [Promises/A+] 查閱到相關(guān)資料.
如果讀者您熟悉 ES6 中的 Promise , 那么對 Promise A+ 規(guī)范一定不陌生, 因為 ES6 中的 Promise 就是基于 Promise A+ 規(guī)范的官方實現(xiàn)和拓展. 我們可以將 ES6 的 Promise 稱為 Promise 對象, 在 ES6 之前, 第三方庫實現(xiàn)的 Promise A+ 規(guī)范對象稱為 thenable 對象.
該規(guī)范旨在于統(tǒng)一 JS 中的異步實現(xiàn), 進而讓回調(diào)變得可控, 避免出現(xiàn)回調(diào)地獄. 早在 ES6 之前, 就有很多第三方庫遵守和支持這個規(guī)范. 比如 jQuery 中的 $.ajax() / $.get()
等方法返回的就是一個 JQuery 實現(xiàn)的 thenable 對象.
因為在 Promise A+ 規(guī)范在社區(qū)中被大范圍認可之前, 各種第三方庫(包括 JavaScript 官方) 對于異步的實現(xiàn)都是不統(tǒng)一的.
這就導(dǎo)致了不同的庫之間如果存在異步, 就很難互相操作.
比如一個 三方庫A 使用異步在 A庫 內(nèi)部某個函數(shù)執(zhí)行的時候返回了數(shù)據(jù) DataA, 現(xiàn)在我需要調(diào)用另一個 第三方庫B 在獲取到 DataA的時候, 執(zhí)行另外一個異步操作. 這是很難操作的, 因為沒有一個統(tǒng)一的規(guī)范告訴 B庫, 我該什么時候執(zhí)行, 每個開發(fā)者的實現(xiàn)是不同的, 為了實現(xiàn)這一點可能就需要建立各種各樣的回調(diào)函數(shù)來相互通訊.
如果時間放眼到現(xiàn)在, 當然很容易實現(xiàn), 只需要一行代碼:
A.then(dataA => { B(dataA).then() });
, 這便是 Promise A+ 規(guī)范的作用.
ES6 Promise
基于 Promise A+ 規(guī)范, 在 ES6 中新增了一個構(gòu)造函數(shù) Promise
, 通過實例化 Promise (new Promise()
) 可以新建一個 Promise 對象, 這個對象是一個符合 Promise A+ 規(guī)范的對象 .
如果為了便于理解, 我們可以將 Promise 對象 簡單理解為一個繼承了 thenable 對象 的對象.
不過在 Promise A+ 的基礎(chǔ)上, ES6還拓展了更多的功能, 比如 .catch()
方法, .finally()
方法 , 靜態(tài)方法 Promise.all()
等等, 具體可以查閱 MDN-Promise .
需要另外了解的一點是, .catch( (error) => {} )
方法本質(zhì)上就是第一個參數(shù)傳入了空參數(shù)的.then( undefined, (error) => {} )
方法.
最小實現(xiàn)的 Promise 和最大實現(xiàn)的 Promise
綜上所述, 我們可以將 Promise A+ 規(guī)范規(guī)定的 Promise 稱為最小實現(xiàn)的 Promise, 也就是 thenable
對象; 將 ES6 的 Promise 成為最大實現(xiàn)的 Promise, 即 Promise
對象.
如果要檢測一個值是否為最小實現(xiàn)的 Promise , 只需要檢測是否函數(shù)/對象, 并且存在 .then()
方法即可.
如果要檢測一個值是否為最大實現(xiàn)的 Promise, 則只需要在上面的檢測的基礎(chǔ)上, 添加一個 .finally()
方法的檢測.
兼容性
由于 ES6 中的 Promise 是吸取 Promise A+ 規(guī)范制定的, 所以也沿用了 Promise A+ 規(guī)范中的內(nèi)容, 比如很少被注意的一點 Promise A+ Point-46: 只要有暴露了兼容 Promise A+ 規(guī)范 .then()
方法的 thenable 對象, 那么這個 thenable 對象就能夠和其它兼容的 thenable 對象互相操作.
This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant
then
method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonablethen
methods.
所以像是 ES6 的 Promise.all()
, ES7 的 asnyc / await
, 都是使用的最小實現(xiàn) Promise 判斷, 也就是如果傳入的對象 / 函數(shù)存在 .then()
方法, 那么就會被當做一個 Promise 去等待兌現(xiàn) / 拒絕.
示例 - async / await
( async () => {
/* await 一個Promise */
console.log( await new Promise( ( resolve ) => {
resolve( 'resole a Promise.' );
} ) );
// -> 'resole a Promise.'
/* await 一個自定義的thenable對象 */
console.log( await {
then( resolve ) {
resolve( 'resole a thenable object.' )
}
} );
// -> 'resole a thenable object.'
/* await 非Promise非thenable對象, 比如一個空對象 */
console.log( await {} );
console.log( await 1 );
// -> {}
// -> 1
// 返回表達式原先的值
/* await 一個空的thenable對象 */
console.log( await { then() {} } );
// 無輸出
// 因為這是一個 thenable 對象, 所以 await 會暫停當前執(zhí)行進程而不是像上面的表達式一樣直接返回表達式的值
// 因為沒有 resolve 或者 reject, 當前執(zhí)行進程被 await 暫停之后永遠不會恢復(fù)進程, 等同于當前執(zhí)行進程(當前async函數(shù))被阻塞了
console.log( 'Test' );
// 不會有輸出了
} )();
什么是Promise
在 Promise A+ 規(guī)范中, Promise 就是一個具有 .then()
方法的函數(shù)或者對象.
在 ES6(ES2015) 中, Promise 是一個構(gòu)造函數(shù), 通過這個構(gòu)造函數(shù)可以實例化一個符合 Promise A+ 規(guī)范的對象.
在 ES7(ES2016) 及其之后的版本, 還可以使用 await / async 去調(diào)用所有符合 Promise A+ 規(guī)范的對象, 包括一些第三方庫自己實現(xiàn)的符合 Promise A+ 規(guī)范的對象.
只要是符合 Promise A+ 規(guī)范的 Promise , 那么它們之間就可以互相操作.
工具函數(shù), 檢測一個對象是否為Promise
通常不會直接使用類似
value instanceof Promise
的判斷, 而是給予 Promise A+ / ES6 Promise 規(guī)范判斷.
最小限定的檢測, 檢測是否為 thenable
對象.
/**
* 判斷傳入?yún)?shù)是否為 Promise (最小實現(xiàn))
* @param { any } value
* @return { boolean } 是否為 Promise
* @description 代碼源于第三方庫 is-promise
* @tutorial https://www.npmjs.com/package/is-promise
* */
function isPromise( value ) {
return !!value
&& (typeof value === 'object' || typeof value === 'function')
&& typeof value.then === 'function';
}
取消了 typeof value === 'function'
的判斷, 因為通過 new Promise()
實例化的值一定是一個對象.文章來源:http://www.zghlxwxcb.cn/news/detail-698927.html
如果想更嚴格一下, 還可以將 .catch()
方法也加進判斷, 也有些工具函數(shù)只判斷 .then()
方法和 .catch()
方法是否存在, 這只看使用者是想如何限定 Promise 的范圍.文章來源地址http://www.zghlxwxcb.cn/news/detail-698927.html
/**
* 判斷傳入?yún)?shù)是否為 Promise (最大實現(xiàn))
* @param { any } value
* @return { boolean } 是否為 Promise
* */
function isStrictPromise( value ) {
return !!value
&& typeof value === 'object'
&& typeof value.then === 'function'
&& typeof value.finally === 'function';
}
到了這里,關(guān)于[JavaScript理論學(xué)習(xí)] 什么是Promise (含如何判斷一個值是Promise)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!