new Promise
(全篇大白話曹傀,你在這里不會(huì)看到別的專有名詞,不會(huì)再有新的疑惑稳摄,一篇把你安排的明明白白藻雪。)
Promise的產(chǎn)生背景
為了讓大家能夠更清晰的了解什么是Promise,在這里我首先需要給大家盡量用通俗易懂的語(yǔ)言介紹下兩個(gè)概念.
1. 瀏覽器處理同步異步機(jī)制
- 首先瀏覽器是多線程的魁索,但是js是單線程的融撞。
- 多線程就是有多條生產(chǎn)流水線,任務(wù)可以分派每一條生產(chǎn)線上粗蔚。單線程就是只能按照js代碼的書寫順序從上到下按照順序執(zhí)行.(瀏覽器只分配給了js單線程,就是這么孤獨(dú)弱小無(wú)助尝偎,完全不是親生的有某有。左右都是肉鹏控,瀏覽器其實(shí)也很無(wú)奈致扯,不是不給js分配多線程,只是單線程會(huì)讓Dom操作產(chǎn)生沖突当辐,等一系列的問(wèn)題抖僵,也是實(shí)在某的辦法。)
- 只有單線程的js,碰到一些非常耗時(shí)的js代碼,比如向后端請(qǐng)求數(shù)據(jù)(比如ajax)缘揪,網(wǎng)速如果進(jìn)入5G++++++時(shí)代耍群,光速一樣义桂,可能不會(huì)有什么影響,就怕重回原始2G,少女已經(jīng)完成了到大嫂的蛻變世吨,請(qǐng)求的數(shù)據(jù)才姍姍來(lái)遲澡刹。數(shù)據(jù)拿到了,然后咱們繼續(xù)按照js代碼書寫順序向下走耘婚,然后又碰到了請(qǐng)求數(shù)據(jù),然后又一個(gè)少女完成了蛻變陆赋,這個(gè)蛻變過(guò)程沐祷,就是你經(jīng)常聽(tīng)到的瀏覽器的阻塞。
- 瀏覽器看著自己的孩子(js)這么難攒岛,心里也是難受啊赖临,為了避免這種阻塞,瀏覽器就想到了一個(gè)辦法灾锯,每逢碰到這種耗時(shí)操作兢榨,就把這種操作,單獨(dú)的放到一個(gè)內(nèi)存空間中(這個(gè)內(nèi)存空間就是我們常說(shuō)的任務(wù)隊(duì)列顺饮,你要是不常說(shuō)吵聪,自動(dòng)忽略常說(shuō)二字),我們寫的js代碼執(zhí)行完之后兼雄,才會(huì)來(lái)到這個(gè)隊(duì)列里面繼續(xù)執(zhí)行吟逝。
2. 什么是回調(diào)函數(shù)?
- 回調(diào)函數(shù)就是我們執(zhí)行一些異步操作的時(shí)候赦肋,執(zhí)行完之后块攒,可以根據(jù)拿到執(zhí)行結(jié)果進(jìn)行一系列操作的一個(gè)函數(shù)。比如ajax請(qǐng)求后臺(tái)數(shù)據(jù)佃乘,請(qǐng)求成功進(jìn)行的操作囱井,我們就可以稱之為回調(diào)函數(shù)。
function ajax() {
var xhr= new xhrRequest();
//onreadystatechange中的操作就是一個(gè)異步操作
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
document.querySelector(".box").innerHTML = xhr.responseText;
}
}
xhr.open("GET", "url", true);
xhr.send();
}
設(shè)想下趣避,我們有很多個(gè)ajax請(qǐng)求庞呕,ajax1,ajax2,ajax3...,后面的請(qǐng)求都需要用到前面的請(qǐng)求值,這樣我們不得不把后面的請(qǐng)求寫到前面一個(gè)請(qǐng)求的回調(diào)函數(shù)里鹅巍,如果只是多增加一層請(qǐng)求千扶,可能對(duì)代碼可讀性并沒(méi)有多大的影響,但是如果是很多層骆捧,我愿意拿你一天不吃飯去打賭澎羞,你肯定是不愿意在這樣的代碼上看下去的。
function ajax() {
var xhr = new xhrRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var xhr2 = new xhrRequest();
xhr2.onreadystatechange = function () {
var xhr3 = new xhrRequest();
xhr3.onreadystatechange = function () {
var xhr4 = new xhrRequest();
xhr4.onreadystatechange = function () {
// ...
}
xhr4.open("GET", `url.php?name=${xhr3.responseText}`, true);
xhr4.send();
}
xhr3.open("GET", `url.php?name=${xhr2.responseText}`, true);
xhr3.send();
}
xhr2.open("GET", `url.php?name=${xhr.responseText}`, true);
xhr2.send();
}
}
xhr.open("GET", "url.php?", true);
xhr.send();
}
看了上面的代碼敛苇,舉起你們的雙手妆绞,大聲告訴我顺呕,你們深深的迷失在里面無(wú)可自拔,如果你沒(méi)有迷失括饶,反而很酸爽株茶,找我我在幫你嵌套100層,是男人就酸爽100層图焰。不說(shuō)100層启盛,幾乎沒(méi)有人在嵌套了18層后,還能從里面逃出來(lái)技羔,這就是傳說(shuō)中的回調(diào)地獄僵闯,為了把受苦受難的猿人們從地獄中解救出來(lái).他來(lái)了,他來(lái)了藤滥,他內(nèi)褲外穿走來(lái)了鳖粟,他就是Promise.
Promise的使用
在長(zhǎng)篇大論之前,我先說(shuō)幾點(diǎn)我在痛苦中總結(jié)的精髓拙绊。這個(gè)再網(wǎng)上其他地方基本是看不到的向图。每次看別人的文章,雖然可能很詳細(xì)标沪,但是對(duì)于當(dāng)時(shí)還是非常小白的我來(lái)說(shuō)根本沒(méi)辦法去理解榄攀。
- .catch就是.then中處理reject的函數(shù)的另一種寫法,當(dāng)在then中有對(duì)reject拋出的數(shù)據(jù)做一些邏輯處理時(shí)谨娜,.catch是不會(huì)觸發(fā)航攒,當(dāng).then中沒(méi)有對(duì)reject拋出的異常做處理時(shí),才會(huì)觸發(fā).catch趴梢。
- .catch寫在一連串.then()之后.then().then().....then().catch()漠畜,無(wú)論哪一個(gè).then里拋出了異常會(huì)觸發(fā).catch。
- promise或者.then()中代碼出錯(cuò)或者主動(dòng)reject()都會(huì)導(dǎo)致拋出異常坞靶。
- 每一個(gè).then中返回的都是一個(gè)Promise對(duì)象憔狞,這也是為啥可以一直.then的原因。
- 只要是異步操作都可以寫在new Promise之中彰阴,在一個(gè)代碼塊之中只能有一個(gè)resolve()||reject(),也就是在這倆出現(xiàn)之后瘾敢,這個(gè)代碼塊之中再次出現(xiàn)都不會(huì)生效,代碼塊就是一個(gè)大括號(hào)包著的東西{ 尿这。簇抵。。}射众。
- 差一點(diǎn)忘記一個(gè)很重要的東西碟摆,resolve(res)中的值,就是你異步操作叨橱,獲取到的值典蜕,然后通過(guò)reslove()傳到.then(res=>{console.log(res)})中断盛,這樣就不用一層套一層的處理數(shù)據(jù),從而避免了回調(diào)地獄的產(chǎn)生愉舔。
function guess大小() {
let num = parseInt(Math.random() * 6 + 1)
return new Promise((resolve, reject) => {
if (num > 3) {
console.log('大');
resolve('then中的大')
console.log('大2');
} else {
console.log('小');
reject('then中的小')
console.log('小2');
}
console.log('開(kāi)始啦1');
setTimeout(() => {
resolve(11111)
console.log(123);
}, 000);
console.log('開(kāi)始啦2');
setTimeout(() => {
console.log(66666666);
}, 2000);
}
)
}
guess大小().then(
//下面這兩個(gè)是es6中函數(shù)的寫法钢猛,詳情參見(jiàn)箭頭函數(shù)
res=>{
//當(dāng)為小時(shí),就不會(huì)進(jìn)入這一層轩缤,下面一層.then中的res就位undefined
console.log(res);
// return '2222'
return new Promise((resolve,reject)=>{
resolve (33333)
})
},
rej=>{
console.log(rej);
}
).then(res=>{
console.log(res);
})
依次打印為
大
大二
開(kāi)始啦1
開(kāi)始啦2
then中的大
'333'
'123'
'456'
'66666666'
通過(guò)上面代碼以及打印結(jié)果命迈,你不難發(fā)現(xiàn),resolve,reject無(wú)論寫在哪里典奉,無(wú)論是同步代碼中或者異步代碼中躺翻,都會(huì)在這個(gè)執(zhí)行之后,執(zhí)行then,resolve和reject也是一個(gè)異步操作卫玖,在和這個(gè)異步操作處于同一個(gè)異步或者同步代碼,優(yōu)于.then中的代碼先執(zhí)行.setTimeout就是一個(gè)異步的代碼,無(wú)論延遲時(shí)間是多少踊淳。
第一次接觸某些知識(shí)可能有些繞假瞬,自己一定要?jiǎng)邮謱?shí)踐下。編程不像是讀書迂尝,你看了很多文章脱茉,就會(huì)對(duì)應(yīng)的增加你很多知識(shí)。開(kāi)發(fā)更多的像是健身垄开,你看的健身相關(guān)方面的知識(shí)再多琴许,帶給你最多的可能就是和別人討論的資本,但他真的對(duì)增加你身上的肌肉沒(méi)有多少幫助溉躲。
想成為大牛榜田,沒(méi)有捷徑可言。擼起你的雙手锻梳,你敲的每一行有效代碼箭券,都會(huì)見(jiàn)證你的成長(zhǎng)。
promise除了以上使用疑枯,還有兩個(gè)不常用的使用方式辩块,如果你感覺(jué)上面的還沒(méi)有徹底理解,你完全可以不看荆永,使用場(chǎng)景很少废亭。
- Promise.all()
- Promise.race()
Promise.all()的使用
all中文含義'所有的',由此我們不難猜測(cè)具钥,Promise.all()就是同時(shí)執(zhí)行多個(gè)Promise對(duì)象的豆村。
let fighting = (time) => {
return new Promise((resolve, reject) => {
console.log(123);
setTimeout(() => {
resolve(`敵人還有${time / 1000}秒到達(dá)戰(zhàn)場(chǎng),全軍出擊`)
}, time)
})
}
let p1 = fighting(5000)
let p2 = fighting(10000)
//注意觀察all參數(shù)數(shù)組中每一項(xiàng)的順序
Promise.all([p1, p2]).then((result) => {
console.log(result) // [ '敵人還有5秒到達(dá)戰(zhàn)場(chǎng)氓拼,全軍出擊', '敵人還有10秒到達(dá)戰(zhàn)場(chǎng)你画,全軍出擊' ]
}).catch((error) => {
console.log(error)
})
Promise.all([p2, p1]).then((result) => {
console.log(result) // [ '敵人還有10秒到達(dá)戰(zhàn)場(chǎng)抵碟,全軍出擊', '敵人還有5秒到達(dá)戰(zhàn)場(chǎng),全軍出擊' ]
}).catch((error) => {
console.log(error)
})
通過(guò)以上代碼不難發(fā)現(xiàn)坏匪,Promise.all()參數(shù)是一個(gè)數(shù)組拟逮,數(shù)組里的一個(gè)個(gè)的Promise對(duì)象,他們傳遞給then的結(jié)果也是一個(gè)數(shù)組适滓,這個(gè)數(shù)組里的順序是和all中數(shù)組順序一一對(duì)應(yīng)的,只有在這個(gè)數(shù)組中所有的Promise對(duì)象都執(zhí)行完成才會(huì)獲得這個(gè)結(jié)果敦迄。catch中會(huì)得到最先捕獲到的錯(cuò)誤。在開(kāi)發(fā)中凭迹,Promise.all()主要使用在需要多個(gè)異步完成后罚屋,才能進(jìn)行的回調(diào)。
Promise.race()的使用
race中文含義'速度'嗅绸,由此我們依然可以很容易猜到脾猛,Promise.race()也是同時(shí)執(zhí)行多個(gè)Promise對(duì)象的。
let fighting = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`敵人還有${time / 1000}秒到達(dá)戰(zhàn)場(chǎng)鱼鸠,全軍出擊`)
}, time)
})
}
let p1 = fighting(10000)
let p2 = fighting(5000)
Promise.race([p1, p2]).then((result) => {
console.log(result)//敵人還有5秒到達(dá)戰(zhàn)場(chǎng)猛拴,全軍出擊
})
Promise.race()中參數(shù)和Promise.all()相同,仍然是一個(gè)數(shù)組蚀狰,數(shù)組里還是一個(gè)一個(gè)的Promise對(duì)象愉昆,不同的是傳遞給then的結(jié)果是這些Promise對(duì)象中最先執(zhí)行完成的那個(gè)所傳遞的,是一個(gè)字符串形式麻蹋。開(kāi)發(fā)中跛溉,幾乎很難碰到Promise.race()的使用場(chǎng)景。
一個(gè)夢(mèng)想開(kāi)飯店卻被迫輾轉(zhuǎn)在前端的榮耀王者渣渣扮授。
說(shuō)在最后的話
千山萬(wàn)水都是情芳室,點(diǎn)點(diǎn)關(guān)注行不行。
萬(wàn)水千山都是愛(ài)糙箍,留個(gè)評(píng)論也不賴渤愁。
全篇都是小編我一個(gè)字一個(gè)字碼出來(lái)的,如果我的文章真的對(duì)你有幫助深夯,還請(qǐng)動(dòng)動(dòng)你發(fā)財(cái)?shù)男∈侄陡瘢ξ以缛臻_(kāi)個(gè)飯店。
賺錢是順便的咕晋,不讓每一個(gè)初入前端的人走我走過(guò)的痛苦是認(rèn)真的雹拄。
本人渣渣,難免不足掌呜,歡迎指正滓玖。