引言
在Javasc里面,所有的代碼都是單線程執(zhí)行的祭衩,所以導致JS中所有的事件都必須異步執(zhí)行浴井。比如setTimeout(callback,1000)
,異步執(zhí)行一般是通過調用回調函數來實現锋八,用的最多的ajax
request.onreadystatechange = function () {
if (request.readyState === 4) {
if (request.status === 200) {
return success(request.responseText);
} else {
return fail(request.status);
}
}
}
把回調函數寫在ajax里面,既不好看也不利于代碼復用护盈,所以Promise出來了
正文
Promise
的語法
new Promise(function(resolve,reject){ //實例一個promise對象
if(true){
resolve("aaaa"); //promise的第一個參數挟纱,表示成功,接下來會執(zhí)行then()
}else{
reject("bbbbb"); //同上腐宋,表示失敗紊服,接下來會執(zhí)行catch()
}
}) //執(zhí)行函數
.then(function(result){console.log(result)}) //resolve調用then() 輸出"aaaa"
.catch(function(reason){console.log(reason)}) //reject調用catch() 輸出"bbbbb"
Promise
的特點
- 對象的狀態(tài)不受外界干擾檀轨,也就是說一旦執(zhí)行了就停不下來,而且執(zhí)行結果也無法更改欺嗤。promise有三種狀態(tài):pending(執(zhí)行中),fulfilled(成功),rejected(失敗)参萄。這三個狀態(tài)其實就是個概念,沒甚用煎饼。
- 狀態(tài)改變后就不會再變讹挎,也就是說函數執(zhí)行完好久好久了,給它加個回調函數它仍然能立即返回結果吆玖。
Promise
連環(huán)使用
new Promise().then().then().then().catch()
上面的代碼依次指定了三個回調函數筒溃,第一then()
執(zhí)行完(必須包含return語句),將返回結果作為參數傳給下一個then()
then()
有兩個參數衰伯,then(function(){},function(){})
第一個是resolve
的回調函數铡羡,第二個可選參數是reject
的回調函數,相當于catch()
意鲸。不過一般不會這樣用烦周,因為Promise對象的錯誤有冒泡的特性,會一直傳遞怎顾,上面例子的catch()
語句可以捕獲三個then()
里面的錯誤读慎,當捕獲到錯誤時,后面的then()
就會跳過槐雾,不再執(zhí)行夭委。
Promise
的執(zhí)行順序
new Promise(function(resolve,reject){
console.log(1)
setTimeout(function(){
console.log(2)
},101)
resolve()
}).then(function(res){
console.log(3)
});
console.log(4)
setTimeout(function(){
console.log(5)
},100)
結果是 1 4 3 5 2
粗淺分析:假如上面的代碼是一個線程的,那么
setTimeout()
其實是在下一個線程上執(zhí)行募强,new Promise()
的參數函數時立即執(zhí)行的株灸,Promise
的then()
這是這當前線程的最末尾執(zhí)行,所以setTimeout()
時最晚執(zhí)行的擎值,先輸出5慌烧,是因為一個是100ms,一個是101ms
finally語句
new Promise().then().catch().finally()
跟try..catch語句一樣鸠儿,finally不管怎樣都要執(zhí)行的
Promise.all()
Promise.all([p1,p2,p3]).then()
參數是Promise實例的數組屹蚊,當P1,P2,P3都執(zhí)行完的時候再執(zhí)行then()
var p1 = new Promise(function(resolve,reject){
resolve(1)
})
var p2 = new Promise(function(resolve,reject){
resolve(2)
})
Promise.all([p1,p2]).then(function(res){
console.log(res) //[1,2]
})
then()
接收的值是所有實例對象返回值組成的數組
Proomise.race()
Promise.race([p1,p2,p3]).then()
跟Promise.all()
類似,不同的是race
哪個實例先執(zhí)行完立馬調用then()
引出async
Promise
有一種情況进每,ajax請求接口返回id,用返回的id去ajax請求另外一個接口,用Promise
實現如下:
var p1 = new Promise(function(resolve,reject){
setTimeout(function(){resolve(1)},100);
})
p1.then(function(id){
new Promise(function(resolve,reject){
setTimeout(function(){resolve(id+1)},100);
}).then(function(name){
console.log(name)
})
})
這僅僅是一次嵌套而且代碼簡單可讀性就很差汹粤,如果多次嵌套那絕對看眼花,所以引入async
函數,用async
重寫
(async function(){
let id = await new Promise(resolve => setTimeout(()=>resolve(1),100))
let name = await new Promise(resolve => setTimeout(()=>resolve(id+1),100))
console.log(name)
})()
從上至下田晚,一目了然
異步函數
存在的意義:提高promise的可讀性
語法:
async function mytest(){
try{
const returnValue = await promise;
}
catch(rejectedValue){
//
}
}
如果在函數開頭使用關鍵字async
,就可以在函數里面使用await
,當await
某個promise時嘱兼,函數會暫停執(zhí)行,直到該promise產生結果贤徒,并且暫停不會阻塞
主線程芹壕。
示例
function logFetch() {
return fetch(url).then(response => responset.text())
.then(text => {
console.log(text);
}).catch(err => {
console.log(err);
})
}
使用異步函數重寫
async function logFetch() {
try{
var response = awit fetch(url);
console.log(response.text());
}
catch(err){
console.log(err);
}
}