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