JavaScript Promise返回值詳解
Promise回顧
Promise回調函數返回非Promise值
Promise回調函數返回Promise對象
Promise回調函數中拋出錯誤
總結
Promise回顧
Promise對象是JavaScript ES6標准中一個重要的內容,它是為了異步而生的,相比於經典的回調函數寫法,在處理大量異步任務時使用Promise鏈在可讀性上會遠遠優於回調函數導致的回調地獄,本文建立在讀者已經對Promise有所了解的情況下,如果你還不了解Promise,可以參考MDN上的這篇文章。
下面我們先來簡要回顧一下Promise對象的性質,如果你已經足夠熟悉,請前往下一節內容。
Promise有三種狀態,如果用Promise()構造器創建一個Promise對象,當被創建時,它的狀態是pending,如果一個Promise對象的resolve方法被調用,它的狀態會變成fulfilled,而如果一個Promise對象的reject方法被調用,它的狀態會變成rejected。此外,還有兩種初始化Promise對象的方法,分別是Promise.resolve方法和Promise.reject方法,前者會直接返回一個狀態為fulfilled的Promise對象而后者會直接返回一個狀態為rejected的Promise對象。
在一個Promise鏈中,如果一個Promise狀態變成了fulfilled,它會自動在Promise鏈中向下尋找,直到發現一個then方法,並執行其中的第一個參數函數,而如果一個Promise的狀態變成了rejected,它會在Promise鏈中向下尋找,直到發現一個帶有兩個參數的then方法並執行它的第二個參數函數或發現一個catch方法並執行它的參數函數。
要知道,Promise.prototype.then和Promise.prototype.catch都會返回一個Promise對象,這是Promise鏈能生效的關鍵,這篇文章討論的重點就是這兩個方法的返回值。
注意:為了增強可讀性,本文中涉及到Promise.prototype.then都只傳入一個參數,作為fulfilled狀態的回調函數,rejected狀態的回調函數在Promise.prototype.catch中定義。
Promise回調函數返回非Promise值
當一個Promise.prototype.then方法被調用時,且在回調函數中返回的值是一個非Promise對象時,它會生成一個狀態為fulfilled的新的Promise對象,並把該返回值傳入下一個回調函數,看下面這個例子:
Promise.resolve().then(function() { return 'Hello World'; }) .then(function(value) { console.log(`fulfilled: ${value}`); // 'fulfilled: Hello World' }) .catch(function(value) { console.log(`rejected: ${value}`); });
我們先用Promise.resolve生成了一個fulfilled狀態的Promise對象以便調用then方法,在它的回調函數中我們返回了一個字符串Hello World,可以看到Promise鏈中第二個then方法的回調函數被調用,打印出了fulfilled: Hello World,說明前一個回調函數的返回值被傳入,且在Promise鏈的上一環節返回的新Promise狀態為fulfilled。
當一個Promise.prototype.catch方法被調用,且在回調函數中返回的值是一個非Promise對象,它仍然會生成一個狀態為fulfilled的新的Promise對象,並把該返回值傳入下一個回調函數,相當於錯誤已經被捕獲,看下面這個例子:
Promise.reject().catch(function() { return 'Hello World'; }) .then(function(value) { console.log(`fulfilled: ${value}`); // 'fulfilled: Hello World' }) .catch(function(value) { console.log(`rejected: ${value}`); })
我們先用Promise.reject生成了一個rejected狀態的Promise對象,這時第一個catch方法觸發,在它的回調函數里返回了字符串Hello World,此后第一個then方法觸發,打印出了fulfilled: Hello World,說明前一個回調函數的返回值被傳入,且在Promise鏈的上一環節返回的新Promise狀態為fulfilled。
你可以動手試試上面的例子,自己嘗試着修改一些代碼並查看返回值,有助於對這一節的內容有更深的理解。
Promise回調函數返回Promise對象
如果Promise的回調函數中返回的是Promise,那么無論觸發的是Promise鏈中的then方法還是catch方法,新生成的Promise對象的狀態都直接取決於回調函數中返回的Promise對象的狀態,傳進下一個回調函數的值也取決於這個被返回的Promise對象,讓我們看下面幾個例子:
Promise.resolve().then(function() { return Promise.resolve('Hello World'); }) .then(function(value) { console.log(`fulfilled: ${value}`); // 'fulfilled: Hello World' }) .catch(function(value) { console.log(`rejected: ${value}`); });
Promise.resolve().then(function() { return Promise.reject('Hello World'); }) .then(function(value) { console.log(`fulfilled: ${value}`); }) .catch(function(value) { console.log(`rejected: ${value}`); // 'rejected: Hello World' });
Promise.reject().catch(function() { return Promise.resolve('Hello World'); }) .then(function(value) { console.log(`fulfilled: ${value}`); // 'fulfilled: Hello World' }) .catch(function(value) { console.log(`rejected: ${value}`); });
Promise.reject().catch(function() { return Promise.reject('Hello World'); }) .then(function(value) { console.log(`fulfilled: ${value}`); }) .catch(function(value) { console.log(`rejected: ${value}`); // 'rejected: Hello World' });
你可以動手試試上面的例子來更深刻地感受一下返回Promise對象與返回其他值時的不同。
通過這幾個例子可以看到,如果回調函數中返回Promise對象,無論是then方法還是catch方法生成的Promise對象都直接取決於回調函數中的這個Promise對象。
Promise回調函數中拋出錯誤
如果Promise的回調函數中拋出了一個錯誤,則會生成一個狀態為rejected的Promise,並將這個錯誤作為參數傳給Promise鏈的下一個回調函數,看下面兩個例子:
Promise.resolve().then(function() { throw new Error('Oops!'); }) .then(function(value) { console.log('fulfilled'); console.log(value.message); }) .catch(function(value) { console.log('rejected'); // 'rejected' console.log(value.message); // 'Oops!' });
Promise.reject().catch(function() { throw new Error('Oops!'); }) .then(function(value) { console.log('fulfilled'); console.log(value.message); }) .catch(function(value) { console.log('rejected'); // 'rejected' console.log(value.message); // 'Oops!' })
你可以動手試試來感受一下這種情況下拋出錯誤對生成的Promise對象的影響。
可以看到,這種情況下catch的回調函數被執行,說明拋出錯誤后,返回的Promise狀態是rejected,並且傳入Promise鏈下一環節的值是這個錯誤對象。
總結
當Promise的回調函數返回非Promise對象的值時,then和catch都生成一個狀態為fulfilled的Promise對象,並把該返回值傳入Promise鏈的下一環節。
當Promise的回調函數返回值為Promise對象時,生成的Promise對象的狀態由被返回的Promise對象決定,傳入Promise鏈下一環節的值也由這個被返回的Promise決定。
當Promise的回調函數中拋出錯誤時,then和catch都生成一個狀態為rejected的Promise對象,並把拋出的錯誤對象傳入Promise鏈的下一環節。