摘要:意味著操作成功完成。方法接收失敗情況的回調(diào)函數(shù)作為參數(shù),返回一個(gè)對(duì)象。參數(shù)回調(diào)函數(shù)不接收任何參數(shù),當(dāng)對(duì)象變成狀態(tài)時(shí)被調(diào)用?,F(xiàn)在各個(gè)方法的參數(shù)返回值功能和使用方法已經(jīng)有個(gè)大概的了解了,為了進(jìn)一步理解其原理,接下來我打算簡(jiǎn)單地實(shí)現(xiàn)一下它。
前言
最近幾周參加筆試面試,總是會(huì)遇到實(shí)現(xiàn)異步和處理異步的問題,然而作者每次都無法完美地回答。在最近一次筆試因?yàn)?Promise 而被刷掉后,我終于下定決心一個(gè)個(gè)地搞懂它們,就先拿 Promise 開刀吧 :)。
用法解析ES6 的Promise對(duì)象是一個(gè)代理對(duì)象,被代理的值在Promise對(duì)象創(chuàng)建時(shí)可能是未知的,另外它允許你為異步操作的成功和失敗分別綁定相應(yīng)的處理方法。
Promise 常用于控制異步操作的執(zhí)行順序,而且可以讓異步方法像同步方法那樣返回值。它不能立即取得異步方法的返回值,但是它可以代理這個(gè)值,一旦異步操作完成,就會(huì)以及將值傳遞給相應(yīng)的處理方法。
一個(gè)Promise對(duì)象有以下幾種狀態(tài):
pending: 初始狀態(tài),既不是成功,也不是失敗狀態(tài)。
fulfilled: 意味著操作成功完成。
rejected: 意味著操作失敗。
一個(gè)Promise對(duì)象的狀態(tài)可以從pending變成fulfilled,同時(shí)傳遞一個(gè)值給相應(yīng)的onfulfilled處理方法;也可以從pending變成rejected,同時(shí)傳遞一個(gè)失敗信息給相應(yīng)的onrejected處理方法。
一旦一個(gè)Promise對(duì)象的狀態(tài)發(fā)生改變,就會(huì)觸發(fā)之前通過Promise.prototype.then、 Promise.prototype.catch和 Promise.prototype.finally方法綁定的onfulfilled、onrejected和onFinally處理方法。
因?yàn)?then、catch和finally方法都會(huì)返回一個(gè)新的Promise對(duì)象, 所以它們可以被鏈?zhǔn)秸{(diào)用。
構(gòu)造函數(shù)Promise()主要用來包裝還未支持 promises 的函數(shù)。
new Promise( function(resolve, reject) {...} /* executor */ );
參數(shù):executor
executor是帶有 resolve 和 reject 兩個(gè)函數(shù)參數(shù)的函數(shù)。Promise構(gòu)造函數(shù)執(zhí)行時(shí)立即調(diào)用executor函數(shù),換句話說,executor函數(shù)是在Promise構(gòu)造函數(shù)內(nèi)執(zhí)行的,所以它是同步代碼。在executor函數(shù)內(nèi)調(diào)用 resolve 和 reject 函數(shù),可以傳遞參數(shù)給相應(yīng)的處理方法,并會(huì)分別將 promise 新建對(duì)象的狀態(tài)改為fulfilled(完成)或rejected(失敗)。
executor 內(nèi)部通常會(huì)執(zhí)行一些異步操作如ajax,一旦完成,可以調(diào)用resolve函數(shù)傳遞參數(shù)并將 promise 對(duì)象的狀態(tài)改成 fulfilled,或者在發(fā)生錯(cuò)誤時(shí)調(diào)用reject 函數(shù)傳遞參數(shù)并將 promise 對(duì)象的狀態(tài)改成 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函數(shù)中拋出一個(gè)錯(cuò)誤,那么該 promise 對(duì)象狀態(tài)將變?yōu)?b>rejected,并將錯(cuò)誤作為參數(shù)傳遞給對(duì)應(yīng)的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(); }); };靜態(tài)方法
靜態(tài)方法是定義在構(gòu)造函數(shù)上的方法,聲明靜態(tài)方法:
Func.fn = function() {}
調(diào)用靜態(tài)方法:
Func.fn(args);
ES6中的Promise構(gòu)造函數(shù)有4個(gè)靜態(tài)方法:
Promise.resolve(value)
Promise.reject(reason)
Promise.all(iterable)
Promise.race(iterable)
Promise.resolve(value):
返回一個(gè)由參數(shù)value解析而來的Promise對(duì)象。
如果傳入的value本身就是Promise對(duì)象,則直接返回value;
如果value是一個(gè)thenable對(duì)象(帶有 then 方法的對(duì)象),返回的Promise對(duì)象會(huì)跟隨這個(gè)thenable對(duì)象,狀態(tài)隨之變化;
其它情況下返回的Promise對(duì)象狀態(tài)為fulfilled,并且將該value作為參數(shù)傳遞給onfulfilled處理方法。
通常而言,如果你不知道一個(gè)值是否為Promise對(duì)象,就可以使用 Promise.resolve(value) 來將value以Promise對(duì)象的形式使用。
// resolve一個(gè)thenable對(duì)象 var p1 = Promise.resolve({ then: function(onFulfill, onReject) { onFulfill("fulfilled!"); } }); console.log(p1 instanceof Promise) // true, 這是一個(gè)Promise對(duì)象 p1.then(function(v) { console.log(v); // 輸出"fulfilled!" }, function(e) { // 不會(huì)被調(diào)用 });
Promise.reject(reason):
返回一個(gè)被給定原因reason拒絕的Promise對(duì)象。
返回的Promise對(duì)象的status狀態(tài)屬性為rejected,reason拒絕原因?qū)傩裕▊鬟f給onrejected處理方法的 reason 參數(shù))與參數(shù)reason相等。
Promise.reject(new Promise((resolve, reject) => resolve("done"))) .then(function(reason) { // 未被調(diào)用 }, function(reason) { console.log(reason); // new Promise });
Promise.all(iterable):
參數(shù):iterable對(duì)象為Array對(duì)象、Map對(duì)象和Set對(duì)象等可迭代對(duì)象。
返回:一個(gè)Promise對(duì)象。
如果iterable不是一個(gè)可迭代對(duì)象,Promise.all會(huì)同步地返回返回一個(gè)狀態(tài)為rejected ,拒絕原因reson為類型錯(cuò)誤的 promise 對(duì)象;
如果iterable對(duì)象為空,Promise.all會(huì)同步地返回一個(gè)狀態(tài)為fulfilled,value值為空數(shù)組的 promise 對(duì)象;
如果iterable對(duì)象中的 promise 對(duì)象都變?yōu)?b>fulfilled狀態(tài),或者iterable對(duì)象內(nèi)沒有 promise 對(duì)象,Promise.all返回的 promise 對(duì)象將異步地變?yōu)?b>fulfilled狀態(tài)。這兩種情況返回的 promise 對(duì)象的value值(傳遞給onfulfilled處理方法的 value 參數(shù))都是一個(gè)數(shù)組,這個(gè)數(shù)組包含iterable對(duì)象中所有的基本值和 promise 對(duì)象value值,這些值將會(huì)按照參數(shù)iterable內(nèi)的順序排列,而不是由 promise 的完成順序決定;
如果iterable對(duì)象中任意一個(gè) promise 對(duì)象狀態(tài)變?yōu)?b>rejected,那么Promise.all就會(huì)異步地返回一個(gè)狀態(tài)為rejected的 promise 對(duì)象,而且此 promise 對(duì)象的reason值(傳遞給onrejected處理方法的 reason 參數(shù)),等于iterable對(duì)象中狀態(tài)為rejected的那一個(gè) promise 對(duì)象的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):
返回一個(gè)Promise對(duì)象。
如果iterable不是一個(gè)可迭代對(duì)象,Promise.race會(huì)同步地返回返回一個(gè)狀態(tài)為rejected,拒絕原因reson為類型錯(cuò)誤的 promise 對(duì)象;
如果iterable對(duì)象為空,Promise.all會(huì)同步地返回一個(gè)狀態(tài)為fulfilled,value值為空數(shù)組的 promise 對(duì)象;
如果iterable對(duì)象不為空,一旦iterable中的某個(gè) promise 對(duì)象完成或拒絕,返回的 promise 對(duì)象就會(huì)完成或拒絕,且返回的 promise 對(duì)象的value值(完成時(shí))或reason值(拒絕時(shí))和這個(gè) promise 對(duì)象的value值(完成時(shí))或reason值(拒絕時(shí))相等。
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"實(shí)例方法
實(shí)例方法是定義在原型對(duì)象上的方法,聲明實(shí)例方法:
Func.prototype.fn = function() {}
調(diào)用實(shí)例方法需要先創(chuàng)建一個(gè)實(shí)例:
let func = new Func(); func.fn(args);
Promise的原型對(duì)象上有3個(gè)實(shí)例方法:
Promise.prototype.then(onFulfilled, onRejected)
Promise.prototype.catch(onRejected)
Promise.prototype.finally(onFinally)
Promise.prototype.then(onFulfilled, onRejected):
then方法接收成功和失敗兩種情況的回調(diào)函數(shù)作為參數(shù),返回一個(gè)Promise對(duì)象。
參數(shù):onFulfilled和onRejected回調(diào)函數(shù)。
onFulfilled:當(dāng) promise 對(duì)象變成 fulfilled 狀態(tài)時(shí)被調(diào)用。onFulfilled函數(shù)有一個(gè)參數(shù),即 promise 對(duì)象完成時(shí)的 value 值。如果onFulfilled不是函數(shù),它會(huì)在then方法內(nèi)部被替換成一個(gè)Identity函數(shù),即 (x) => (x) 。
onRejected:當(dāng) promise 對(duì)象變成 rejected 狀態(tài)時(shí)被調(diào)用。onRejected函數(shù)有一個(gè)參數(shù),即 promise 對(duì)象失敗時(shí)的 reason 值。如果onRejected不是函數(shù),它會(huì)在then方法內(nèi)部被替換成一個(gè)Thrower函數(shù),即 (reason) => {throw reason} 。
返回:一旦調(diào)用then方法的 promise 對(duì)象被完成或拒絕,將異步調(diào)用相應(yīng)的處理函數(shù)(onFulfilled或onRejected),即將處理函數(shù)加入microtask隊(duì)列中。如果onFulfilled或onRejected回調(diào)函數(shù):
返回一個(gè)值,則then返回的 promise 對(duì)象的status變?yōu)?b>fulfilled,value變?yōu)榛卣{(diào)函數(shù)的返回值;
不返回任何內(nèi)容,則then返回的 promise 對(duì)象的status變?yōu)?b>fulfilled,value變?yōu)?b>undefined;
拋出一個(gè)錯(cuò)誤,則then返回的 promise 對(duì)象的status變?yōu)?b>rejected,reason變?yōu)榛卣{(diào)函數(shù)拋出的錯(cuò)誤;
返回一個(gè)狀態(tài)為fulfilled的 promise 對(duì)象,則then返回的 promise 對(duì)象的status變?yōu)?b>fulfilled,value等于回調(diào)函數(shù)返回的 promise 對(duì)象的value值;
返回一個(gè)狀態(tài)為rejected的 promise 對(duì)象,則then返回的 promise 對(duì)象的status變?yōu)?b>rejected,reason等于回調(diào)函數(shù)返回的 promise 對(duì)象的reason值;
返回一個(gè)狀態(tài)為pending的 promise 對(duì)象,則then返回的 promise 對(duì)象的status變?yōu)?b>pending,且其status將隨著回調(diào)函數(shù)返回的 promise 對(duì)象的status變化而變化,之后其value或reason值也會(huì)和此 promise 對(duì)象的value或reason值相同。
這里提一下,這個(gè)地方看 MDN 文檔中文翻譯實(shí)在看不懂,之后看英文原文反而稍微理解了,希望之后在實(shí)現(xiàn) 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方法接收失敗情況的回調(diào)函數(shù)作為參數(shù),返回一個(gè)Promise對(duì)象。
參數(shù):onRejected回調(diào)函數(shù),表現(xiàn)同then中的onRejected參數(shù)。
返回:promiseObj.catch(onRejected) 與 promiseObj.then(undefined, onRejected) 返回值相同。
Promise.resolve() .then( () => { // 返回一個(gè) 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回調(diào)函數(shù)作為參數(shù),返回一個(gè)Promise對(duì)象。
如果你想在 promise 執(zhí)行完畢后,無論其結(jié)果是成功還是失敗,都做一些相同的處理時(shí),可以使用finally方法。
參數(shù):onFinally回調(diào)函數(shù)
onFinally不接收任何參數(shù),當(dāng) promise 對(duì)象變成 settled (fulfilled / rejected) 狀態(tài)時(shí)onFinally被調(diào)用。
返回:如果onFinally回調(diào)函數(shù)
不返回任何內(nèi)容或者返回一個(gè)值或者返回一個(gè)狀態(tài)為fulfilled的 promise 對(duì)象,則finally返回的 promise 對(duì)象的status、value和reason值與調(diào)用這個(gè)finally方法的 promise 對(duì)象的值相同;
拋出一個(gè)錯(cuò)誤或者返回一個(gè)狀態(tài)為rejected的 promise 對(duì)象,則finally返回的 promise 對(duì)象的status值變?yōu)?b>rejected,reason值變?yōu)楸粧伋龅腻e(cuò)誤或者回調(diào)函數(shù)返回的 promise 對(duì)象的reason值;
返回一個(gè)狀態(tài)為pending的 promise 對(duì)象,則finally返回的 promise 對(duì)象的status值變?yōu)?b>pending,且其status值將隨著回調(diào)函數(shù)返回的 promise 對(duì)象的status值變化而變化,之后其value或reason值也會(huì)和此 promise 對(duì)象的value或reason值相同。
Promise.reject("是我,開心嗎").finally(function() { var pro = new Promise(function(r){r("你得不到我")}); //pro.status === "fulfilled" return pro; //`onFinally`回調(diào)函數(shù)返回一個(gè)狀態(tài)為`fulfilled`的 promise 對(duì)象 }).catch(function(reason) { console.log(reason); });結(jié)語(yǔ)
將 MDN 文檔整理了一下,加入了一些自己的理解,也花費(fèi)了一天的時(shí)間。現(xiàn)在Promise各個(gè)方法的參數(shù)、返回值、功能和使用方法已經(jīng)有個(gè)大概的了解了,為了進(jìn)一步理解其原理,接下來我打算簡(jiǎn)單地實(shí)現(xiàn)一下它。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/102577.html
摘要:在和方法執(zhí)行的時(shí)候訂閱事件,將自己的回調(diào)函數(shù)綁定到事件上,屬性是發(fā)布者,一旦它的值發(fā)生改變就發(fā)布事件,執(zhí)行回調(diào)函數(shù)。實(shí)現(xiàn)和方法的回調(diào)函數(shù)都是,當(dāng)滿足條件對(duì)象狀態(tài)改變時(shí),這些回調(diào)會(huì)被放入隊(duì)列。所以我需要在某個(gè)變?yōu)闀r(shí),刪除它們綁定的回調(diào)函數(shù)。 前言 按照文檔說明簡(jiǎn)單地實(shí)現(xiàn) ES6 Promise的各個(gè)方法并不難,但是Promise的一些特殊需求實(shí)現(xiàn)起來并不簡(jiǎn)單,我首先提出一些不好實(shí)現(xiàn)或者容...
摘要:的翻譯文檔由的維護(hù)很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:理解承諾有兩個(gè)部分。如果異步操作成功,則通過的創(chuàng)建者調(diào)用函數(shù)返回預(yù)期結(jié)果,同樣,如果出現(xiàn)意外錯(cuò)誤,則通過調(diào)用函數(shù)傳遞錯(cuò)誤具體信息。這將與理解對(duì)象密切相關(guān)。這個(gè)函數(shù)將創(chuàng)建一個(gè),該將在到秒之間的隨機(jī)數(shù)秒后執(zhí)行或。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:理解承諾有兩個(gè)部分。如果異步操作成功,則通過的創(chuàng)建者調(diào)用函數(shù)返回預(yù)期結(jié)果,同樣,如果出現(xiàn)意外錯(cuò)誤,則通過調(diào)用函數(shù)傳遞錯(cuò)誤具體信息。這將與理解對(duì)象密切相關(guān)。這個(gè)函數(shù)將創(chuàng)建一個(gè),該將在到秒之間的隨機(jī)數(shù)秒后執(zhí)行或。 想閱讀更多優(yōu)質(zhì)文章請(qǐng)猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! showImg(https://segmentfault.com/img/bVbkNvF?w=1280&h=...
摘要:當(dāng)前的部分代碼狀態(tài)超時(shí)再縮小了范圍以后,進(jìn)一步進(jìn)行排查。函數(shù)是一個(gè)很簡(jiǎn)單的一次性函數(shù),在第一次被觸發(fā)時(shí)調(diào)用函數(shù)。因?yàn)樯鲜鍪褂玫氖牵?,所以在獲取的時(shí)候,肯定為空,那么這就意味著會(huì)繼續(xù)調(diào)用函數(shù)。 有時(shí)候,所見并不是所得,有些包,你需要去翻他的源碼才知道為什么會(huì)這樣。 背景 今天調(diào)試一個(gè)程序,用到了一個(gè)很久之前的NPM包,名為formstream,用來將form表單數(shù)據(jù)轉(zhuǎn)換為流的形式進(jìn)行...
閱讀 2398·2021-09-22 16:01
閱讀 3163·2021-09-22 15:41
閱讀 1181·2021-08-30 09:48
閱讀 496·2019-08-30 15:52
閱讀 3335·2019-08-30 13:57
閱讀 1719·2019-08-30 13:55
閱讀 3670·2019-08-30 11:25
閱讀 767·2019-08-29 17:25