摘要:意味著操作成功完成。方法接收失敗情況的回調函數作為參數,返回一個對象。參數回調函數不接收任何參數,當對象變成狀態時被調用。現在各個方法的參數返回值功能和使用方法已經有個大概的了解了,為了進一步理解其原理,接下來我打算簡單地實現一下它。
前言
最近幾周參加筆試面試,總是會遇到實現異步和處理異步的問題,然而作者每次都無法完美地回答。在最近一次筆試因為 Promise 而被刷掉后,我終于下定決心一個個地搞懂它們,就先拿 Promise 開刀吧 :)。
用法解析ES6 的Promise對象是一個代理對象,被代理的值在Promise對象創建時可能是未知的,另外它允許你為異步操作的成功和失敗分別綁定相應的處理方法。
Promise 常用于控制異步操作的執行順序,而且可以讓異步方法像同步方法那樣返回值。它不能立即取得異步方法的返回值,但是它可以代理這個值,一旦異步操作完成,就會以及將值傳遞給相應的處理方法。
一個Promise對象有以下幾種狀態:
pending: 初始狀態,既不是成功,也不是失敗狀態。
fulfilled: 意味著操作成功完成。
rejected: 意味著操作失敗。
一個Promise對象的狀態可以從pending變成fulfilled,同時傳遞一個值給相應的onfulfilled處理方法;也可以從pending變成rejected,同時傳遞一個失敗信息給相應的onrejected處理方法。
一旦一個Promise對象的狀態發生改變,就會觸發之前通過Promise.prototype.then、 Promise.prototype.catch和 Promise.prototype.finally方法綁定的onfulfilled、onrejected和onFinally處理方法。
因為 then、catch和finally方法都會返回一個新的Promise對象, 所以它們可以被鏈式調用。
構造函數Promise()主要用來包裝還未支持 promises 的函數。
new Promise( function(resolve, reject) {...} /* executor */ );
參數:executor
executor是帶有 resolve 和 reject 兩個函數參數的函數。Promise構造函數執行時立即調用executor函數,換句話說,executor函數是在Promise構造函數內執行的,所以它是同步代碼。在executor函數內調用 resolve 和 reject 函數,可以傳遞參數給相應的處理方法,并會分別將 promise 新建對象的狀態改為fulfilled(完成)或rejected(失敗)。
executor 內部通常會執行一些異步操作如ajax,一旦完成,可以調用resolve函數傳遞參數并將 promise 對象的狀態改成 fulfilled,或者在發生錯誤時調用reject 函數傳遞參數并將 promise 對象的狀態改成 rejected。如下:
function myAsyncFunction(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = () => reject(xhr.statusText); xhr.send(); }); };
如果在executor函數中拋出一個錯誤,那么該 promise 對象狀態將變為rejected,并將錯誤作為參數傳遞給對應的onrejected處理方法。如下:
function myAsyncFunction(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onerror = () => { throw xhr.statusText; //throw xhr.statusText 效果等同于 reject(xhr.statusText) }; xhr.send(); }); };靜態方法
靜態方法是定義在構造函數上的方法,聲明靜態方法:
Func.fn = function() {}
調用靜態方法:
Func.fn(args);
ES6中的Promise構造函數有4個靜態方法:
Promise.resolve(value)
Promise.reject(reason)
Promise.all(iterable)
Promise.race(iterable)
Promise.resolve(value):
返回一個由參數value解析而來的Promise對象。
如果傳入的value本身就是Promise對象,則直接返回value;
如果value是一個thenable對象(帶有 then 方法的對象),返回的Promise對象會跟隨這個thenable對象,狀態隨之變化;
其它情況下返回的Promise對象狀態為fulfilled,并且將該value作為參數傳遞給onfulfilled處理方法。
通常而言,如果你不知道一個值是否為Promise對象,就可以使用 Promise.resolve(value) 來將value以Promise對象的形式使用。
// resolve一個thenable對象 var p1 = Promise.resolve({ then: function(onFulfill, onReject) { onFulfill("fulfilled!"); } }); console.log(p1 instanceof Promise) // true, 這是一個Promise對象 p1.then(function(v) { console.log(v); // 輸出"fulfilled!" }, function(e) { // 不會被調用 });
Promise.reject(reason):
返回一個被給定原因reason拒絕的Promise對象。
返回的Promise對象的status狀態屬性為rejected,reason拒絕原因屬性(傳遞給onrejected處理方法的 reason 參數)與參數reason相等。
Promise.reject(new Promise((resolve, reject) => resolve("done"))) .then(function(reason) { // 未被調用 }, function(reason) { console.log(reason); // new Promise });
Promise.all(iterable):
參數:iterable對象為Array對象、Map對象和Set對象等可迭代對象。
返回:一個Promise對象。
如果iterable不是一個可迭代對象,Promise.all會同步地返回返回一個狀態為rejected ,拒絕原因reson為類型錯誤的 promise 對象;
如果iterable對象為空,Promise.all會同步地返回一個狀態為fulfilled,value值為空數組的 promise 對象;
如果iterable對象中的 promise 對象都變為fulfilled狀態,或者iterable對象內沒有 promise 對象,Promise.all返回的 promise 對象將異步地變為fulfilled狀態。這兩種情況返回的 promise 對象的value值(傳遞給onfulfilled處理方法的 value 參數)都是一個數組,這個數組包含iterable對象中所有的基本值和 promise 對象value值,這些值將會按照參數iterable內的順序排列,而不是由 promise 的完成順序決定;
如果iterable對象中任意一個 promise 對象狀態變為rejected,那么Promise.all就會異步地返回一個狀態為rejected的 promise 對象,而且此 promise 對象的reason值(傳遞給onrejected處理方法的 reason 參數),等于iterable對象中狀態為rejected的那一個 promise 對象的reason值。
// this will be counted as if the iterable passed is empty, so it gets fulfilled var p = Promise.all([1,2,3]); // this will be counted as if the iterable passed contains only the resolved promise with value "333", so it gets fulfilled var p2 = Promise.all([1,2,3, Promise.resolve(333)]); // this will be counted as if the iterable passed contains the rejected promise with value "444", so it gets rejected var p3 = Promise.all([1,2, Promise.reject(444), Promise.reject(555)]); // using setTimeout we can execute code after the stack is empty setTimeout(function(){ console.log(p); console.log(p2); console.log(p3); }); // logs // Promise {: "fulfilled", : Array[3] } // Promise { : "fulfilled", : Array[4] } // Promise { : "rejected", : 444 }
Promise.race(iterable):
返回一個Promise對象。
如果iterable不是一個可迭代對象,Promise.race會同步地返回返回一個狀態為rejected,拒絕原因reson為類型錯誤的 promise 對象;
如果iterable對象為空,Promise.all會同步地返回一個狀態為fulfilled,value值為空數組的 promise 對象;
如果iterable對象不為空,一旦iterable中的某個 promise 對象完成或拒絕,返回的 promise 對象就會完成或拒絕,且返回的 promise 對象的value值(完成時)或reason值(拒絕時)和這個 promise 對象的value值(完成時)或reason值(拒絕時)相等。
var promise1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, "one"); }), promise2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, "two"); }); Promise.race([promise1, promise2]).then(function(value) { console.log(value); // Both resolve, but promise2 is faster }); // expected output: "two"實例方法
實例方法是定義在原型對象上的方法,聲明實例方法:
Func.prototype.fn = function() {}
調用實例方法需要先創建一個實例:
let func = new Func(); func.fn(args);
Promise的原型對象上有3個實例方法:
Promise.prototype.then(onFulfilled, onRejected)
Promise.prototype.catch(onRejected)
Promise.prototype.finally(onFinally)
Promise.prototype.then(onFulfilled, onRejected):
then方法接收成功和失敗兩種情況的回調函數作為參數,返回一個Promise對象。
參數:onFulfilled和onRejected回調函數。
onFulfilled:當 promise 對象變成 fulfilled 狀態時被調用。onFulfilled函數有一個參數,即 promise 對象完成時的 value 值。如果onFulfilled不是函數,它會在then方法內部被替換成一個Identity函數,即 (x) => (x) 。
onRejected:當 promise 對象變成 rejected 狀態時被調用。onRejected函數有一個參數,即 promise 對象失敗時的 reason 值。如果onRejected不是函數,它會在then方法內部被替換成一個Thrower函數,即 (reason) => {throw reason} 。
返回:一旦調用then方法的 promise 對象被完成或拒絕,將異步調用相應的處理函數(onFulfilled或onRejected),即將處理函數加入microtask隊列中。如果onFulfilled或onRejected回調函數:
返回一個值,則then返回的 promise 對象的status變為fulfilled,value變為回調函數的返回值;
不返回任何內容,則then返回的 promise 對象的status變為fulfilled,value變為undefined;
拋出一個錯誤,則then返回的 promise 對象的status變為rejected,reason變為回調函數拋出的錯誤;
返回一個狀態為fulfilled的 promise 對象,則then返回的 promise 對象的status變為fulfilled,value等于回調函數返回的 promise 對象的value值;
返回一個狀態為rejected的 promise 對象,則then返回的 promise 對象的status變為rejected,reason等于回調函數返回的 promise 對象的reason值;
返回一個狀態為pending的 promise 對象,則then返回的 promise 對象的status變為pending,且其status將隨著回調函數返回的 promise 對象的status變化而變化,之后其value或reason值也會和此 promise 對象的value或reason值相同。
這里提一下,這個地方看 MDN 文檔中文翻譯實在看不懂,之后看英文原文反而稍微理解了,希望之后在實現 Promise 的過程中能理解更深。
var fromCallback; var fromThen = Promise.resolve("done") .then(function() { fromCallback = new Promise(function(){}); return fromCallback; }); setTimeout(function() { console.log(fromCallback); //fromCallback.status === "pending" console.log(fromThen); //fromThen.status === "pending" console.log(fromCallback === fromThen); //false }, 0);
Promise.prototype.catch(onRejected):
catch方法接收失敗情況的回調函數作為參數,返回一個Promise對象。
參數:onRejected回調函數,表現同then中的onRejected參數。
返回:promiseObj.catch(onRejected) 與 promiseObj.then(undefined, onRejected) 返回值相同。
Promise.resolve() .then( () => { // 返回一個 rejected promise throw "Oh no!"; }) .catch( reason => { console.error( "onRejected function called: ", reason ); }) .then( () => { console.log( "I am always called even if the prior then"s promise rejects" ); });
Promise.prototype.finally(onFinally):
finally方法接收onFinally回調函數作為參數,返回一個Promise對象。
如果你想在 promise 執行完畢后,無論其結果是成功還是失敗,都做一些相同的處理時,可以使用finally方法。
參數:onFinally回調函數
onFinally不接收任何參數,當 promise 對象變成 settled (fulfilled / rejected) 狀態時onFinally被調用。
返回:如果onFinally回調函數
不返回任何內容或者返回一個值或者返回一個狀態為fulfilled的 promise 對象,則finally返回的 promise 對象的status、value和reason值與調用這個finally方法的 promise 對象的值相同;
拋出一個錯誤或者返回一個狀態為rejected的 promise 對象,則finally返回的 promise 對象的status值變為rejected,reason值變為被拋出的錯誤或者回調函數返回的 promise 對象的reason值;
返回一個狀態為pending的 promise 對象,則finally返回的 promise 對象的status值變為pending,且其status值將隨著回調函數返回的 promise 對象的status值變化而變化,之后其value或reason值也會和此 promise 對象的value或reason值相同。
Promise.reject("是我,開心嗎").finally(function() { var pro = new Promise(function(r){r("你得不到我")}); //pro.status === "fulfilled" return pro; //`onFinally`回調函數返回一個狀態為`fulfilled`的 promise 對象 }).catch(function(reason) { console.log(reason); });結語
將 MDN 文檔整理了一下,加入了一些自己的理解,也花費了一天的時間。現在Promise各個方法的參數、返回值、功能和使用方法已經有個大概的了解了,為了進一步理解其原理,接下來我打算簡單地實現一下它。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102577.html
摘要:在和方法執行的時候訂閱事件,將自己的回調函數綁定到事件上,屬性是發布者,一旦它的值發生改變就發布事件,執行回調函數。實現和方法的回調函數都是,當滿足條件對象狀態改變時,這些回調會被放入隊列。所以我需要在某個變為時,刪除它們綁定的回調函數。 前言 按照文檔說明簡單地實現 ES6 Promise的各個方法并不難,但是Promise的一些特殊需求實現起來并不簡單,我首先提出一些不好實現或者容...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:理解承諾有兩個部分。如果異步操作成功,則通過的創建者調用函數返回預期結果,同樣,如果出現意外錯誤,則通過調用函數傳遞錯誤具體信息。這將與理解對象密切相關。這個函數將創建一個,該將在到秒之間的隨機數秒后執行或。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:理解承諾有兩個部分。如果異步操作成功,則通過的創建者調用函數返回預期結果,同樣,如果出現意外錯誤,則通過調用函數傳遞錯誤具體信息。這將與理解對象密切相關。這個函數將創建一個,該將在到秒之間的隨機數秒后執行或。 想閱讀更多優質文章請猛戳GitHub博客,一年百來篇優質文章等著你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:當前的部分代碼狀態超時再縮小了范圍以后,進一步進行排查。函數是一個很簡單的一次性函數,在第一次被觸發時調用函數。因為上述使用的是,而非,所以在獲取的時候,肯定為空,那么這就意味著會繼續調用函數。 有時候,所見并不是所得,有些包,你需要去翻他的源碼才知道為什么會這樣。 背景 今天調試一個程序,用到了一個很久之前的NPM包,名為formstream,用來將form表單數據轉換為流的形式進行...
閱讀 2386·2021-09-22 16:01
閱讀 3153·2021-09-22 15:41
閱讀 1171·2021-08-30 09:48
閱讀 490·2019-08-30 15:52
閱讀 3324·2019-08-30 13:57
閱讀 1713·2019-08-30 13:55
閱讀 3649·2019-08-30 11:25
閱讀 757·2019-08-29 17:25