摘要:如果改變已經(jīng)發(fā)生了,你再對(duì)對(duì)象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果。其次,如果不設(shè)置回調(diào)函數(shù),內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。
作為一個(gè)入門級(jí)前端,今天是一個(gè)非常值得紀(jì)念的日子,因?yàn)檫@是我第一次在論壇上發(fā)表帖子,作為起步。雖然我覺得自己水平還是十分的有限,對(duì)一些細(xì)節(jié)的理解還不是很透徹,但是還是要邁出這一步,不管是給別的新手作為學(xué)習(xí)參考,還是自己以后回顧,總覺得需要把自己的成長(zhǎng)記錄下來,希望自己以后還是要多堅(jiān)持,如果有不對(duì)的地方還是希望大家及時(shí)提出來,共同進(jìn)步
今天有時(shí)間翻到了es6的promise,可能大家都對(duì)此熟悉不過,我之前一直覺得promise也很簡(jiǎn)單,但是今天確實(shí)讓我對(duì)promise有了一個(gè)新的了解,以前的理解可能是錯(cuò)誤的。。。先來看看官方的promise的定義是:
所謂Promise,簡(jiǎn)單說就是一個(gè)容器,里面保存著某個(gè)未來才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語法上說,Promise 是一個(gè)對(duì)象,從它可以獲取異步操作的消息。Promise 提供統(tǒng)一的 API,各種異步操作都可以用同樣的方法進(jìn)行處理。
特點(diǎn):
(1)對(duì)象的狀態(tài)不受外界影響。Promise對(duì)象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失?。?。只有異步操作的結(jié)果,可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無法改變這個(gè)狀態(tài)。這也是Promise這個(gè)名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變
(2)一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果。Promise對(duì)象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會(huì)再變了,會(huì)一直保持這個(gè)結(jié)果,這時(shí)就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了,你再對(duì)Promise對(duì)象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果。這與事件(Event)完全不同,事件的特點(diǎn)是,如果你錯(cuò)過了它,再去監(jiān)聽,是得不到結(jié)果的。
初讀上面這段話我讀了不下5次,但是我還是沒能真正了解其真正表達(dá)的意思,于是我查閱了部分資料,終于找到了一個(gè)比較容易理解的說法,這個(gè)估計(jì)小白應(yīng)該是可以看得懂得。
就拿做飯吃飯洗碗來舉例子吧,這是三個(gè)步驟,第一步做飯,再第二步吃飯的時(shí)候我們需要拿到第一步做的飯,在第三步洗碗的時(shí)候我們需要拿到第二步的碗筷,而且這三個(gè)步驟必須是按照順序執(zhí)行,有嚴(yán)格的先后順序。
//做飯
function cook(){
console.log("開始做飯。");
var p = new Promise(function(resolve, reject){ //做一些異步操作
setTimeout(function(){
console.log("做飯完畢!");
resolve("雞蛋炒飯");
}, 1000);
});
return p;
}
//吃飯
function eat(data){
console.log("開始吃飯:" + data);
var p = new Promise(function(resolve, reject){ //做一些異步操作
setTimeout(function(){
console.log("吃飯完畢!");
resolve("一個(gè)碗和一雙筷子");
}, 2000);
});
return p;
}
//洗碗
function wash(data){
console.log("開始洗碗:" + data);
var p = new Promise(function(resolve, reject){ //做一些異步操作
setTimeout(function(){
console.log("洗碗完畢!");
resolve("干凈的碗筷");
}, 2000);
});
return p;
}
//函數(shù)調(diào)用
cook().then(res1 => {
console.log(res1,"這是第一步傳遞給第二步的參數(shù)")
return eat(res1)
}).then(res2 => {
console.log(res2,"這是第二步傳給第三步的參數(shù)")
return wash(res2)
}).then(res3 => {
console.log(res3,"飯吃完了還你干凈的碗筷")
})
結(jié)果如下:
看完上面的代碼大家可能會(huì)有好多疑問,我在這里把我當(dāng)時(shí)初學(xué)promise的疑問和大家分享一下:
答:Promise也有一些缺點(diǎn)。首先,無法取消Promise,一旦新建它就會(huì)立即執(zhí)行,無法中途取消。其次,如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤,不會(huì)反應(yīng)到外部。第三,當(dāng)處于pending狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成)。
這是promise的一些缺點(diǎn),一旦新建它就會(huì)立即執(zhí)行 所以為了控制這個(gè)promise對(duì)象什么時(shí)候執(zhí)行,在開發(fā)過程中我們需要在外面包裹一個(gè)函數(shù),通過調(diào)用函數(shù)的形式來控制promise的執(zhí)行。大家可以在自己的編輯器中試試。
new Promise(function(resolve, reject) {
setTimeout(()=> {
console.log("開車?。?!")
},2000)
});
答:因?yàn)?strong>有了Promise對(duì)象,就可以將異步操作以同步操作的流程表達(dá)出來,避免了層層嵌套的回調(diào)函數(shù)。此外,Promise對(duì)象提供統(tǒng)一的接口,使得控制異步操作更加容易。
//函數(shù)調(diào)用
cook().then(res1 => {
console.log(res1,"這是第一步傳遞給第二步的參數(shù)")
return eat(res1)
}).then(res2 => {
console.log(res2,"這是第二步傳給第三步的參數(shù)")
return wash(res2)
}).then(res3 => {
console.log(res3,"飯吃完了還你干凈的碗筷")
})
大家看我的這段代碼 在執(zhí)行了cook()函數(shù)的時(shí)候cook函數(shù)return出來一個(gè)promise對(duì)象,promise對(duì)象上有.then()或.catch()方法,那么直接cook().then就可以在.then()方法中我們可以拿到promise對(duì)象中向外傳遞的參數(shù),這個(gè)參數(shù)我們將傳遞給下一個(gè)eat()函數(shù),作為eat()函數(shù)的參數(shù)繼續(xù)執(zhí)行。 而eat()函數(shù)也return了一個(gè)promise對(duì)象。那么我們將我們的這段代碼拆解一下:
第一步: cook() //拿到的是cook return出來的promise對(duì)象
第二步: cook().then(res => {
console.log(res) //拿到內(nèi)部向外部傳遞的參數(shù)
})
第三步: cook().then(res => {
console.log(res)
return eat(res) //eat執(zhí)行以后return的是eat的promise對(duì)象,然后再把這個(gè)對(duì)象繼續(xù)向外return
}) //那么第三步的最終結(jié)果就是eat()的promise對(duì)象
第四步: cook().then(res => {
console.log(res)
return eat(res) //此時(shí)的結(jié)果是eat()的promise對(duì)象
}).then(res2 => {
// 此時(shí)eat的promise又有.then方法 .....以此類推
})
我們就這樣一步一步的完成了整個(gè)做飯、吃飯、洗碗的整個(gè)流程。 縱觀以上代碼你會(huì)發(fā)現(xiàn)雖然每一個(gè)操作流程中我都是以異步函數(shù)setTimeout來進(jìn)行的,但是在調(diào)用過程中確是按照 做飯-吃飯-洗碗的正常流程表達(dá)的。這不是promise的有了Promise對(duì)象,就可以將異步操作以同步操作的流程表達(dá)出來,避免了層層嵌套的回調(diào)函數(shù)
//做飯
function cook(){
console.log("開始做飯。");
var p = new Promise(function(resolve, reject){ //做一些異步操作
setTimeout(function(){
console.log("飯糊了....沒法吃");
reject("糊了的飯");
}, 1000);
});
return p;
}
//吃飯
function eat(data){
console.log("開始吃飯:" + data);
var p = new Promise(function(resolve, reject){ //做一些異步操作
setTimeout(function(){
console.log("吃飯完畢!");
resolve("一個(gè)碗和一雙筷子");
}, 2000);
});
return p;
}
cook().then(res1 => {
console.log(res1,"這是第一步傳遞給第二步的參數(shù)")
return eat(res1)
}).catch(err => {
console.log(err,"返回錯(cuò)誤")
})
catch()方法用來指定 reject 的回調(diào)。
function tackBus1(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log("甲正在上車");
resolve("甲坐好了");
}, 1000);
});
return p;
}
function tackBus2(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log("乙正在上車");
resolve("乙坐好了");
}, 2000);
});
return p;
}
function tackBus3(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log("丙正在上車");
resolve("丙坐好了");
}, 3000);
});
return p;
}
Promise.all([tackBus1(),tackBus2(),tackBus3()]).then(res => {
console.log(res)
})
司機(jī)在等人上車,在乘客都坐穩(wěn)了以后開車發(fā)車,這就用Promise.all來執(zhí)行,all接收一個(gè)數(shù)組參數(shù),里面的值最終都算返回Promise對(duì)象。這樣,三個(gè)異步操作的并行執(zhí)行的,等到它們都執(zhí)行完后才會(huì)進(jìn)到then里面。那么,三個(gè)異步操作返回的數(shù)據(jù)哪里去了呢?都在then里面呢,all會(huì)把所有異步操作的結(jié)果放進(jìn)一個(gè)數(shù)組中傳給then,就是上面的results。所以上面代碼的輸出結(jié)果就是:
這是.all的方法,promise還有一種.race的方法,它和all方法的區(qū)別就是: all方法的效果實(shí)際上是誰跑的慢,以誰為準(zhǔn)執(zhí)行回調(diào),那么相對(duì)的就有另一個(gè)方法誰跑的快,以誰為準(zhǔn)執(zhí)行回調(diào),剛剛的執(zhí)行結(jié)果我設(shè)置了他們的時(shí)間間隔分別是1s,2s,3s,在等最慢的執(zhí)行完以后才執(zhí)行了all這個(gè)回調(diào)方法,現(xiàn)在咱們來試試promise.race方法
function tackBus1(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log("甲正在上車");
resolve("甲坐好了");
}, 1000);
});
return p;
}
function tackBus2(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log("乙正在上車");
resolve("乙坐好了");
}, 2000);
});
return p;
}
function tackBus3(){
var p = new Promise(function(resolve, reject){
//做一些異步操作
setTimeout(function(){
console.log("丙正在上車");
resolve("丙坐好了");
}, 3000);
});
return p;
}
Promise.race([tackBus1(),tackBus2(),tackBus3()]).then(res => {
console.log(res)
})
結(jié)果如下:
在看到promise的時(shí)候有一個(gè)地方還是令我有困惑,現(xiàn)在先留一個(gè)懸念,大家可以先看看下面這段代碼,你覺得輸出結(jié)果是什么呢? 我們下回見!
setTimeout(function(){
console.log("1")
});
new Promise(function(resolve){
console.log("2");
resolve();
}).then(function(){
console.log("3")
});
console.log("4");
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/6835.html
摘要:事件循環(huán)背景是一門單線程非阻塞的腳本語言,單線程意味著,代碼在執(zhí)行的任何時(shí)候,都只有一個(gè)主線程來處理所有的任務(wù)。在意識(shí)到該問題之際,新特性中的可以讓成為一門多線程語言,但實(shí)際開發(fā)中使用存在著諸多限制。這個(gè)地方被稱為執(zhí)行棧。 事件循環(huán)(Event Loop) 背景 JavaScript是一門單線程非阻塞的腳本語言,單線程意味著,JavaScript代碼在執(zhí)行的任何時(shí)候,都只有一個(gè)主線程來...
摘要:這種問題在設(shè)置倒計(jì)時(shí)的經(jīng)常遇到,倒計(jì)時(shí)開始的時(shí)候設(shè)置的時(shí)間是從服務(wù)器拿到的系統(tǒng)時(shí)間很準(zhǔn)確,但是如果后面不定期像服務(wù)期請(qǐng)求系統(tǒng)時(shí)間進(jìn)行校準(zhǔn)的話,你可能會(huì)發(fā)現(xiàn)倒計(jì)時(shí)的偏差越來越來大,這就是主線程執(zhí)行的時(shí)間比設(shè)定的延遲時(shí)間長(zhǎng)導(dǎo)致的。 關(guān)于js執(zhí)行機(jī)制,老早之前就一直想寫篇文章做個(gè)總結(jié),因?yàn)楹蚸s執(zhí)行順序的面試題碰到的特別多,每次碰到總是會(huì)去網(wǎng)上查,沒有系統(tǒng)地總結(jié),搞得每次碰到都是似懂非懂的感...
摘要:如果沒有其他異步任務(wù)要處理比如到期的定時(shí)器,會(huì)一直停留在這個(gè)階段,等待請(qǐng)求返回結(jié)果。執(zhí)行的執(zhí)行事件關(guān)閉請(qǐng)求的,例如事件循環(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ù) ...
摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。 雖然今年沒有換工作的打算 但為了跟上時(shí)代的腳步 還是忍不住整理了一份最新前端知識(shí)點(diǎn) 知識(shí)點(diǎn)匯總 1.HTML HTML5新特性,語義化瀏覽器的標(biāo)準(zhǔn)模式和怪異模式xhtml和html的區(qū)別使用data-的好處meta標(biāo)簽canvasHTML廢棄的標(biāo)簽IE6 bug,和一些定位寫法css js放置位置和原因...
摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。 雖然今年沒有換工作的打算 但為了跟上時(shí)代的腳步 還是忍不住整理了一份最新前端知識(shí)點(diǎn) 知識(shí)點(diǎn)匯總 1.HTML HTML5新特性,語義化瀏覽器的標(biāo)準(zhǔn)模式和怪異模式xhtml和html的區(qū)別使用data-的好處meta標(biāo)簽canvasHTML廢棄的標(biāo)簽IE6 bug,和一些定位寫法css js放置位置和原因...
閱讀 1381·2019-08-30 15:44
閱讀 2148·2019-08-30 13:49
閱讀 1751·2019-08-26 13:54
閱讀 3568·2019-08-26 10:20
閱讀 3430·2019-08-23 17:18
閱讀 3363·2019-08-23 17:05
閱讀 2199·2019-08-23 15:38
閱讀 1087·2019-08-23 14:35