摘要:實(shí)例生成以后,用方法分別指定狀態(tài)和狀態(tài)的回調(diào)函數(shù)。則是或的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。上述代碼也可以理解成這樣處理和前一個(gè)回調(diào)函數(shù)運(yùn)行時(shí)發(fā)生的錯(cuò)誤發(fā)生錯(cuò)誤方法用于指定不管對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行的回調(diào)函數(shù)。
什么是promise?
Promise(承諾),在程序中的意思就是承諾我過一段時(shí)間(通常是一個(gè)異步操作)后會(huì)給你一個(gè)結(jié)果,是異步編程的一種解決方案。從語法上說,原生Promise 是一個(gè)對(duì)象,從它可以獲取異步操作的消息。
promise的特點(diǎn)對(duì)象的狀態(tài)不受外界影響。
promise有三種狀態(tài) pending(進(jìn)行中) fulfilled(已成功) rejected(已失敗),只有異步操作的結(jié)果,才可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無法改變這個(gè)狀態(tài)。
一旦從等待狀態(tài)變成為其他狀態(tài)就永遠(yuǎn)不能更改狀態(tài)了。
promise只有兩種狀態(tài)改變:
pending(進(jìn)行中)--> fulfilled(已成功) ;
pending(進(jìn)行中)--> rejected(已失敗)。
當(dāng)狀態(tài)改變結(jié)束時(shí)稱為resolve(已固定),一旦狀態(tài)變?yōu)?resolved 后,就不能再次改變?yōu)?b>Fulfilled。
一旦新建Promise就會(huì)立即執(zhí)行,無法中途取消。
如果不設(shè)置回調(diào)函數(shù)callback,Promise內(nèi)部拋出的錯(cuò)誤,就不會(huì)反應(yīng)到外部。
當(dāng)處于pending狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。
promise實(shí)例操作首先創(chuàng)造了一個(gè)Promise實(shí)例
let promise=new Promsie(function(resolve,rejec){ if(/*異步執(zhí)行成功*/){ resolve(value); }else{ reject(error); } }) promise.then(function(){ //回調(diào)執(zhí)行成功之后的操作 },function(){ //回調(diào)執(zhí)行失敗之后的操作,可選 });
Promise構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù),該函數(shù)的兩個(gè)參數(shù)分別是resolve和reject。它們是兩個(gè)函數(shù),由 JavaScript 引擎提供。當(dāng)異步操作成功時(shí)(pending--fulfilled),調(diào)用resolve(value)函數(shù)把操作結(jié)果當(dāng)成參數(shù)傳出,當(dāng)異步操作成功時(shí)(pending--rejected)調(diào)用 reject(error)函數(shù)把錯(cuò)誤返回。Promise實(shí)例生成以后,用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)。
下面看一下構(gòu)造函數(shù)原型的方法
Promise.prototype.then()
Promise.prototype.then()作用是為 Promise 實(shí)例添加狀態(tài)改變時(shí)的回調(diào)函數(shù)。接受兩個(gè)回調(diào)函數(shù)作為參數(shù)。第一個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞esolved時(shí)調(diào)用,第二個(gè)回調(diào)函數(shù)是Promise對(duì)象的狀態(tài)變?yōu)閞ejected時(shí)調(diào)用。其中,第二個(gè)函數(shù)是可選的,不一定要提供。
而Promise.prototype.then()返回的是另一個(gè)Promise對(duì)象,后面還可以接著調(diào)用then方法。
Promise.prototype.catch()
Promise.prototype.catch()則是.then(null, rejection)或.then(undefined, rejection)的別名,用于指定發(fā)生錯(cuò)誤時(shí)的回調(diào)函數(shù)。 Promise 對(duì)象的錯(cuò)誤具有“冒泡”性質(zhì),會(huì)一直向后傳遞,直到被捕獲為止。也就是說,錯(cuò)誤總是會(huì)被下一個(gè)catch語句捕獲。
Promise.catch()方法返回的也是一個(gè) Promise 對(duì)象,因此后面還可以接著調(diào)用then方法。
上述代碼也可以理解成這樣:
getJSON("/posts.json").then(function(posts) { // ... }).catch(function(error) { // 處理 getJSON 和 前一個(gè)回調(diào)函數(shù)運(yùn)行時(shí)發(fā)生的錯(cuò)誤 console.log("發(fā)生錯(cuò)誤!", error); });
Promise.prototype.finally()
finally方法用于指定不管 Promise 對(duì)象最后狀態(tài)如何,都會(huì)執(zhí)行的回調(diào)函數(shù)。該方法是 ES2018 引入標(biāo)準(zhǔn)的。
finally方法的回調(diào)函數(shù)不接受任何參數(shù),這意味著沒有辦法知道,前面的 Promise 狀態(tài)到底是fulfilled還是rejected。這表明,finally方法里面的操作,應(yīng)該是與狀態(tài)無關(guān)的,不依賴于 Promise 的執(zhí)行結(jié)果。
finally本質(zhì)上是then方法的特例。
promise.then(()=>{}).catch(()=>{}).finally(() => { // 操作 }); // 等同于 promise.then(result => { // 操作 return result; }).catch( error => { // 操作 throw error; });
promise的鏈?zhǔn)秸{(diào)用
由于 .then每次調(diào)用返回的都是一個(gè)新的Promise實(shí)例,如果then中返回的是一個(gè)結(jié)果的話會(huì)把這個(gè)結(jié)果傳遞下一次then中的成功回調(diào),所以可以鏈?zhǔn)秸{(diào)用該實(shí)例。
如果then中出現(xiàn)異常,會(huì)走下一個(gè)then的失敗回調(diào),catch 會(huì)捕獲到?jīng)]有捕獲的異常。
在 then中使用了return,那么 return 的值會(huì)被Promise.resolve() 包裝,then中也可以不傳遞參數(shù),如果不傳遞會(huì)透到下一個(gè)then中。
Promise.resolve(1).then(res => { console.log(res) return 2 //包裝成 Promise.resolve(2) }).catch(err => 3).then().then(res => console.log(res))promise自身API
Promise.resolve()
將現(xiàn)有的對(duì)象轉(zhuǎn)換(包裝)成 promise對(duì)象。
四種參數(shù)類型:
不帶參數(shù)傳遞 --- 返回一個(gè)新的狀態(tài)為resolve的promise對(duì)象。
let p = Priomse.resolve() // p就是promise
參數(shù)是一個(gè) Promise 實(shí)例--- 返回 當(dāng)前的promise實(shí)例
參數(shù)是帶then方法的對(duì)象
let data = { then:function(resolve,reject){ resovle("帶then方法的對(duì)象") } } Promise.resolve(data).thne((res)=> console.log(res)) // "帶then方法的對(duì)象"
返回一個(gè)新的promise,并直接執(zhí)行then的方法,promise對(duì)象的狀態(tài)就變?yōu)?b>resolved,從而立即執(zhí)行最后那個(gè)then方法指定的回調(diào)函數(shù),輸出 "帶then方法的對(duì)象"。
參數(shù)是非空,非then方法的對(duì)象,非proimse的
let p = Promise.resolve("foo") // 等價(jià)于 let p = new Promise(resolve => resolve("foo")) p.then(res=>console.log(res)) //"foo"
返回一個(gè)新的狀態(tài)為resolve的promise對(duì)象,所以then回調(diào)函數(shù)會(huì)立即執(zhí)行。Promise.resolve方法的參數(shù),會(huì)同時(shí)傳給回調(diào)函數(shù)。
Promise.reject()
參數(shù)為非then對(duì)象時(shí)-----Promise.reject(reason)方法也會(huì)返回一個(gè)新的 Promise 實(shí)例,該實(shí)例的狀態(tài)為rejected
let p = Promise.reject("error") // 等價(jià)于 let p = new Primose((resolve,reject)=>reject("出錯(cuò)了")}) //處理錯(cuò)誤的回調(diào) p.then((null,res)=>console.log(res)) //"出錯(cuò)了"
參數(shù)是帶then方法的對(duì)象 ---返回的并不是then方法的回調(diào)函數(shù),而是data對(duì)象本身
let data = { then:function(resolve,reject){ reject("帶then方法的對(duì)象出錯(cuò)了") } } Promise.resolve(data).thne((null,res)=> console.log(res)) // data //等同于 Promise.resolve(data).catch(res=> console.log(res)) // data
Promise.all()
該方法將多個(gè)promise實(shí)例,包裝成一個(gè)新的promise實(shí)例。
let p = Promise.all([p1,p2,p3])
參數(shù)不一定為數(shù)組,但必須為一個(gè)可迭代Iterator ,且返回的每個(gè)成員(p1,p2,p3)都是 Promise 實(shí)例,如果不是,就會(huì)先調(diào)用的Promise.resolve方法,將參數(shù)轉(zhuǎn)為 Promise 實(shí)例,再進(jìn)一步處理。
var p = Promise.all([1,2,3]); var p2 = Promise.all([1,2,3, Promise.resolve(444)]); var p3 = Promise.all([1,2,3, Promise.reject(555)]); setTimeout(function() { console.log(p);// Promise {: "fulfilled", : Array[3] } console.log(p2); // Promise { : "fulfilled", : Array[4] } console.log(p3); // Promise { : "rejected", : 555 } }); p.then(function (posts) { // ..當(dāng)有返回值的時(shí)候才會(huì)回調(diào) }).catch(function(reason){ // ... });
當(dāng)p1,p2,p3中得實(shí)例都改變成 fulfilled(已成功)時(shí),此時(shí)p1、p2、p3的返回值組成一個(gè)數(shù)組,傳遞給p的回調(diào)函數(shù)。
當(dāng)p1,p2,p3中得實(shí)例其中一項(xiàng)的改變成 rejected(已失敗)時(shí),p的狀態(tài)就變成rejected,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì)傳遞給p的回調(diào)函數(shù)。
Promise.all()是異步解析,只有這當(dāng)所有實(shí)例的狀態(tài)都變成fulfilled,或者其中有一個(gè)變?yōu)?b>rejected,才會(huì)調(diào)用Promise.all方法后面的回調(diào)函數(shù)then,catch方法。但是當(dāng)且僅當(dāng)傳遞的iterable為空時(shí),Promise.all才會(huì)同步解析。
var p = Promise.all([]); console.log(p);//Promise {: "fulfilled", : Array[0] }
處理錯(cuò)誤,常規(guī)情況下,當(dāng)其中一個(gè)實(shí)例返回rejected,就會(huì)調(diào)用Promise.all的catch方法,返回第一個(gè)錯(cuò)誤。但實(shí)際應(yīng)用時(shí),我們想讓所有的實(shí)例不論成功或失敗就可以返回參數(shù)組成數(shù)組,這時(shí)就可以調(diào)用實(shí)例自身的catch方法來規(guī)避這種情況。
const p1 = new Promise((resolve, reject) => { resolve("hello"); //resolved }).then(result => result).catch(e => e); const p2 = new Promise((resolve, reject) => { throw new Error("報(bào)錯(cuò)了");//rejected }).then(result => result).catch(e => e); Promise.all([p1, p2]) .then(result => console.log(result))// ["hello", Error: 報(bào)錯(cuò)了] .catch(e => console.log(e));
p1會(huì)resolved,p2首先會(huì)rejected,但是p2有自己的catch方法,該方法返回的是一個(gè)新的 Promise 實(shí)例,p2指向的實(shí)際上是這個(gè)實(shí)例。該實(shí)例執(zhí)行完catch方法后,也會(huì)變成resolved,導(dǎo)致Promise.all()方法參數(shù)里面的兩個(gè)實(shí)例都會(huì)resolved,因此會(huì)調(diào)用then方法指定的回調(diào)函數(shù),而不會(huì)調(diào)用catch方法指定的回調(diào)函數(shù)。
js原生實(shí)現(xiàn)Promise.all的原理
//在Promise類上添加一個(gè)all方法,接受一個(gè)傳進(jìn)來的promise數(shù)組 Promise.all = function (promiseArrs) { return new Promise((resolve, reject) => { //返回一個(gè)新的Promise let arr = []; //定義一個(gè)空數(shù)組存放結(jié)果 let i = 0; function handleData(index, data) { //處理數(shù)據(jù)函數(shù) arr[index] = data; i++; if (i === promiseArrs.length) { //當(dāng)i等于傳遞的數(shù)組的長度時(shí) resolve(arr); //執(zhí)行resolve,并將結(jié)果放入 } } for (let i = 0; i < promiseArrs.length; i++) { //循環(huán)遍歷數(shù)組 promiseArrs[i].then((data) => { handleData(i, data); //將結(jié)果和索引傳入handleData函數(shù) }, reject) } }) }
如果說all體驗(yàn)不好,那我們也可以自己做一個(gè)some方法,表示全部失敗才算失敗
Promise.some = function (promiseArrs) { return new Promise((resolve, reject) => { let arr = []; //定義一個(gè)空數(shù)組存放結(jié)果 let i = 0; function handleErr(index, err) { //處理錯(cuò)誤函數(shù) arr[index] = err; i++; if (i === promiseArrs.length) { //當(dāng)i等于傳遞的數(shù)組的長度時(shí) reject(err); //執(zhí)行reject,并將結(jié)果放入 } } for (let i = 0; i < promiseArrs.length; i++) { //循環(huán)遍歷數(shù)組 promiseArrs[i].then(resolve, (e) => handleErr(i, e)) } }) }
Promise.allSettled -- 兼容性不友好
該方法和promise.all類似,就是解決all方法在處理錯(cuò)誤時(shí)的不合理而出現(xiàn)的。其參數(shù)接受一個(gè)Promise的數(shù)組, 返回一個(gè)新的Promise, 唯一與all的不同在于, 其不會(huì)進(jìn)行短路, 也就是說當(dāng)Promise全部處理完成后我們可以拿到每個(gè)Promise的狀態(tài), 而不管其是否處理成功。
和all類似,當(dāng)自身實(shí)例有catch回調(diào)時(shí),每個(gè)實(shí)例狀態(tài)變?yōu)?b>fulfilled
const p3 = new Promise((resolve, reject) => { resolve("hello"); //resolved }).then(result => result).catch(e => e); const p4 = new Promise((resolve, reject) => { throw new Error("報(bào)錯(cuò)了");//rejected }).then(result => result).catch(e => e); Promise.allSettled([p3, p4]) .then(result => console.log(result)) .catch(e => console.log(e)); //.then的log //[{status: "fulfilled", value: "hello"},{status: "fulfilled", reason: Error: 報(bào)錯(cuò)了 at:6:10 at new Promise ( ) at :5:13}]
沒有catch接收錯(cuò)誤,返回自身的狀態(tài)和回調(diào)參數(shù)
const p5 = new Promise((resolve, reject) => { resolve("hello"); //resolved }).then(result => result) const p6 = new Promise((resolve, reject) => { throw new Error("報(bào)錯(cuò)了");//rejected }).then(result => result) Promise.allSettled([p5, p6]) .then(result => console.log(result)) .catch(e => console.log(e)); //.then的log //[{status: "fulfilled", value: "hello"},{status: "rejected", reason: Error: 報(bào)錯(cuò)了 at:6:10 at new Promise ( ) at :5:13}]
Promise.race()
該方法同樣是將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例,其他特點(diǎn)和all很像,和all的區(qū)別在于:race方法好比是賽跑,幾個(gè)實(shí)例一起跑,誰先到就成功了,就resolve誰,或者誰跑到中途摔了出現(xiàn)異常狀況失敗了,就reject誰,不論成功還是失敗,就先捕獲第一個(gè)完成的。
捕獲第一個(gè)成功的實(shí)例回調(diào)函數(shù)
let p1 = Promise.resolve("1") let p2 = Promise.resolve("2") Promise.race([p1,p2]).then(res=>conseloe.log(res))// "1"
捕獲第一個(gè)結(jié)果
let p1 = Promise.resolve("1"); let p2 = Promise.reject("ERR2"); Promise.race([p1,p2]).then(res=>conseloe.log(res)) //Promise {: "1"}
捕獲第一個(gè)錯(cuò)誤
let p1 = Promise.reject("ERR1"); let p2 = Promise.reject("ERR2"); Promise.race([p1,p2]).catch(console.log) //Promise {: "ERR1"}
原生實(shí)現(xiàn)Promise.race()的設(shè)計(jì)原理
Promise._race = iterator =>{ return new Promise((resolve,reject)=>{ iterator.forEach(item=>{ Promise.resolve(item).then(resolve).catch(reject) }) }) }
Promise.try-- 提案
在實(shí)際開發(fā)使用promise時(shí),希望經(jīng)過promise包裝后的函數(shù)內(nèi)部代碼讓同步函數(shù)同步執(zhí)行,異步函數(shù)異步執(zhí)行,并且讓它們具有統(tǒng)一的 API
例:當(dāng)同步函數(shù)被promise包裝后的執(zhí)行順序改變。
let fn = () =>console.log("同步1"); Promise.resolve().then(fn) console.log("同步2") //log后 //"同步2" //"同步1"
解決讓同步函數(shù)同步執(zhí)行,異步函數(shù)異步執(zhí)行現(xiàn)階段方法
方法一:使用async匿名函數(shù),會(huì)立即執(zhí)行里面的async函數(shù),因此如果f是同步的,就會(huì)得到同步的結(jié)果;如果f是異步的,就可以用then指定下一步,如果想捕獲錯(cuò)誤,使用catch方法。
let fn = () =>console.log("同步1"); (async ()=>fn())() .then(resolve) .catch(err=>console.log(err)) console.log("同步2") //log后 //"同步1" //"同步2"
方法二:使用promise立即執(zhí)行的匿名函數(shù)
let fn = () =>console.log("同步1"); ( () => new Promise( resolve => resolve(fn()) ))() console.log("同步2") //log后 //"同步1" //"同步2"
Promise.try的應(yīng)用
該方法是用來模擬try的代碼塊的,就像promise.catch模擬的是catch代碼塊。
理解 try catch finally
try catch是JavaScript的異常處理機(jī)制,把可能出錯(cuò)的代碼放在try語句塊中,如果出錯(cuò)了,就會(huì)被catch捕獲來處理異常。如果不catch 一旦出錯(cuò)就會(huì)造成程序崩潰。finally:無論結(jié)果如何,允許在 try 和 catch 之后執(zhí)行代碼。
try { // 供測試的代碼塊 } catch(err) { //處理錯(cuò)誤的代碼塊 } finally { //無論 try / catch 結(jié)果如何都執(zhí)行的代碼塊 }
應(yīng)用
let fn = () => console.log("同步1"); Promise.try(fn); console.log("同步2"); //"同步1" //"同步2"
over~有問題留言
拓展:
什么是Iterator ?
異步編程是什么? 異步編程都有哪些解決方案?
如何使用promise實(shí)現(xiàn)ajax,封裝axios?
如何使用純原生js實(shí)現(xiàn)promise?
借鑒:
https://blog.csdn.net/sjw1039...
http://es6.ruanyifeng.com/#do...
https://developer.mozilla.org...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106813.html
摘要:的翻譯文檔由的維護(hù)很多人說,阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。寫一個(gè)符合規(guī)范并可配合使用的寫一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問題描述 在開發(fā)過程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過...
摘要:前端基礎(chǔ)進(jìn)階正是圍繞這條線索慢慢展開,而事件循環(huán)機(jī)制,則是這條線索的最關(guān)鍵的知識(shí)點(diǎn)。特別是中正式加入了對(duì)象之后,對(duì)于新標(biāo)準(zhǔn)中事件循環(huán)機(jī)制的理解就變得更加重要。之后全局上下文進(jìn)入函數(shù)調(diào)用棧。 showImg(https://segmentfault.com/img/remote/1460000008811705); JavaScript的學(xué)習(xí)零散而龐雜,因此很多時(shí)候我們學(xué)到了一些東西,但...
摘要:如果沒有其他異步任務(wù)要處理比如到期的定時(shí)器,會(huì)一直停留在這個(gè)階段,等待請求返回結(jié)果。執(zhí)行的執(zhí)行事件關(guān)閉請求的,例如事件循環(huán)的每一次循環(huán)都需要依次經(jīng)過上述的階段。因此,才會(huì)早于執(zhí)行。 showImg(https://segmentfault.com/img/bVbnY76); 概念 同步任務(wù)(Synchronous) 在主線程上排隊(duì)執(zhí)行的任務(wù),只有前一個(gè)任務(wù)執(zhí)行完畢,才能執(zhí)行后一個(gè)任務(wù) ...
摘要:異步過程控制了解異步的意義之后,我們來對(duì)比目前主流幾種異步過程控制方法,探討一下異步編程的最佳實(shí)踐。結(jié)語希望本文對(duì)大家有點(diǎn)幫助,能更深刻的理解異步編程,能寫出更優(yōu)雅更高效的代碼。 同步和異步(Synchronous and Asynchronous) 了解javascript的同學(xué)想必對(duì)同步和異步的概念應(yīng)該都很熟悉了,如果還有不熟悉的同學(xué),我這里舉個(gè)形象的例子,比如我們早上起床后要干三...
閱讀 2779·2021-10-14 09:42
閱讀 837·2021-10-11 10:57
閱讀 781·2019-08-30 15:54
閱讀 1925·2019-08-30 13:50
閱讀 1692·2019-08-30 11:19
閱讀 940·2019-08-29 12:38
閱讀 1430·2019-08-26 11:51
閱讀 1399·2019-08-26 10:48