https://www.cnblogs.com/lvdabao/p/es6-promise-1.html 講得很好
一、鏈?zhǔn)讲僮鞯挠梅?、resolve() 的用法
<script>
console.dir(Promise);
function fun0() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)0");
resolve('隨便什么數(shù)據(jù)0')
}, 1000)
})
return p
}
function fun1() {
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)1");
resolve('隨便什么數(shù)據(jù)1')
}, 1000)
})
return p1
}
function fun2() {
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)2");
resolve('隨便什么數(shù)據(jù)2')
}, 1000)
})
return p2
}
function fun3() {
var p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)3-");
resolve('隨便什么數(shù)據(jù)3')
}, 1000)
})
return p3
}
fun0().then((data) => {
console.log(data);
return fun1()
}).then((data) => {
console.log(data);
return fun2()
}).then((data) => {
console.log(data+`結(jié)束`);
// return fun3()
})
</script>
二、reject的用法
<script>
function getNum() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
var num = Math.ceil(Math.random() * 10) //生成1-10的隨機(jī)數(shù)
num <= 5 ? resolve(num) : reject('數(shù)字不符合')
}, 500)
})
return p
}
getNum().then(
(data) => {
console.log('resolved');
console.log(data);
},
//then的第二個(gè)參數(shù),用來指定reject的回調(diào)
(reason, data) => { //調(diào)用reject并傳遞一個(gè)參數(shù),作為失敗的原因。
console.log('rejected');
console.log(reason);
}
)
</script>
有兩種結(jié)果:
狀態(tài)置為fullfiled

或者
狀態(tài)置為rejected

三、catch的用法
我們知道Promise對(duì)象實(shí)例可以共享 Promise 構(gòu)造函數(shù)上的then、catch、finally等方法,catch和then的第二個(gè)參數(shù)一樣,用來指定reject的回調(diào),用法是這樣:
function getNum() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
var num = Math.ceil(Math.random() * 10) ////生成1-10的隨機(jī)數(shù)
num <= 5 ? resolve(num) : reject('數(shù)字不符合')
}, 500)
})
return p
}
getNum().then(
(data) => {
console.log('resolved');
console.log(data);
}
// (reason, data) => {
// console.log('rejected');
// console.log(reason);
// }
).catch(function (reason) {
console.log('rejected'); //效果和寫在then的第二個(gè)參數(shù)里面一樣。
console.log(reason);
})
效果和寫在then的第二個(gè)參數(shù)里面一樣。不過它還有另外一個(gè)作用:在執(zhí)行resolve的回調(diào)(也就是上面then中的第一個(gè)參數(shù))時(shí),如果拋出異常了(代碼出錯(cuò)了),那么并不會(huì)報(bào)錯(cuò)卡死js,而是會(huì)進(jìn)到這個(gè)catch方法中。請(qǐng)看下面的代碼:
<script>
function getNum() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
var num = Math.ceil(Math.random() * 10) ////生成1-10的隨機(jī)數(shù)
num <= 5 ? resolve(num) : reject('數(shù)字不符合')
}, 500)
})
return p
}
getNum().then(
(data) => {
console.log('resolved');
console.log(data);
console.log(somedata); //此處的somedata未定義
}
// (reason, data) => {
// console.log('rejected');
// console.log(reason);
// }
).catch(function (reason) { //效果和寫在then的第二個(gè)參數(shù)里面一樣。
console.log('rejected');
console.log(reason);
})
</script>

也就是說進(jìn)到catch方法里面去了,而且把錯(cuò)誤原因傳到了reason參數(shù)中。即便是有錯(cuò)誤的代碼也不會(huì)報(bào)錯(cuò)了,這與我們的try/catch語句有相同的功能。
四、all的用法
Promise的all方法提供了并行執(zhí)行異步操作的能力,并且在所有異步操作執(zhí)行完后才執(zhí)行回調(diào)。我們?nèi)耘f使用上面定義好的fun0(), fun1(), fun2(), fun3()這四個(gè)函數(shù),看下面的例子:
<script>
console.dir(Promise);
function fun0() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)0");
resolve('隨便什么數(shù)據(jù)0')
}, 1000)
})
return p
}
function fun1() {
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)1");
resolve('隨便什么數(shù)據(jù)1')
}, 1000)
})
return p1
}
function fun2() {
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)2");
resolve('隨便什么數(shù)據(jù)2')
}, 1000)
})
return p2
}
function fun3() {
var p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)3-");
resolve('隨便什么數(shù)據(jù)3')
}, 1000)
})
return p3
}
// fun0().then((data) => {
// console.log(data);
// return fun1()
// }).then((data) => {
// console.log(data);
// return fun2()
// }).then((data) => {
// console.log(data + `結(jié)束`);
// // return fun3()
// })
Promise.all([fun0(), fun1(), fun2(), fun3()]).then((results) => {
console.log(results);
})
</script>
用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,你就可以并行執(zhí)行多個(gè)異步操作,并且在一個(gè)回調(diào)中處理所有的返回?cái)?shù)據(jù),是不是很酷?有一個(gè)場景是很適合用這個(gè)的,一些游戲類的素材比較多的應(yīng)用,打開網(wǎng)頁時(shí),預(yù)先加載需要用到的各種資源如圖片、flash以及各種靜態(tài)文件。所有的都加載完后,我們?cè)龠M(jìn)行頁面的初始化。
五、race的用法
all方法的效果實(shí)際上是「誰跑的慢,以誰為準(zhǔn)執(zhí)行回調(diào)」,那么相對(duì)的就有另一個(gè)方法「誰跑的快,以誰為準(zhǔn)執(zhí)行回調(diào)」,這就是race方法,這個(gè)詞本來就是賽跑的意思。race的用法與all一樣,我們把上面fun0(), fun1(), fun2(), fun3()的延時(shí)改一下來看一下:
<script>
console.dir(Promise);
function fun0() {
var p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)0");
resolve('隨便什么數(shù)據(jù)0')
}, 1000)
})
return p
}
function fun1() {
var p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)1");
resolve('隨便什么數(shù)據(jù)1')
}, 2000)
})
return p1
}
function fun2() {
var p2 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)2");
resolve('隨便什么數(shù)據(jù)2')
}, 3000)
})
return p2
}
function fun3() {
var p3 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("執(zhí)行完成任務(wù)3-");
resolve('隨便什么數(shù)據(jù)3')
}, 4000)
})
return p3
}
// fun0().then((data) => {
// console.log(data);
// return fun1()
// }).then((data) => {
// console.log(data);
// return fun2()
// }).then((data) => {
// console.log(data + `結(jié)束`);
// // return fun3()
// })
Promise.race([fun0(), fun1(), fun2(), fun3()]).then((results) => {
console.log(results);
})

你猜對(duì)了嗎?不完全,是吧。在then里面的回調(diào)開始執(zhí)行時(shí),fun1(), fun2(), fun3()并沒有停止,仍舊再執(zhí)行。于是再過1秒后,輸出了他們結(jié)束的標(biāo)志。
這個(gè)race有什么用呢?使用場景還是很多的,比如我們可以用race給某個(gè)異步請(qǐng)求設(shè)置超時(shí)時(shí)間,并且在超時(shí)后執(zhí)行相應(yīng)的操作,代碼如下:
<script>
//請(qǐng)求某個(gè)圖片資源
function requestImg() {
var p = new Promise(function (resolve, reject) {
var img = new Image();
img.onload = function () {
resolve(img);
}
img.src = 'https://www.baidu.com/';
});
return p;
}
//延時(shí)函數(shù),用于給請(qǐng)求計(jì)時(shí)
function timeout() {
var p = new Promise(function (resolve, reject) {
setTimeout(function () {
reject('圖片請(qǐng)求超時(shí)');
}, 5000);
});
return p;
}
Promise
.race([requestImg(), timeout()])
.then(function (results) {
console.log(results);
})
.catch(function (reason) {
console.log(reason);
});
</script>
requestImg函數(shù)會(huì)異步請(qǐng)求一張圖片,我把地址寫為"xxxxxx",所以肯定是無法成功請(qǐng)求到的。timeout函數(shù)是一個(gè)延時(shí)5秒的異步操作。我們把這兩個(gè)返回Promise對(duì)象的函數(shù)放進(jìn)race,于是他倆就會(huì)賽跑,如果5秒之內(nèi)圖片請(qǐng)求成功了,那么遍進(jìn)入then方法,執(zhí)行正常的流程。如果5秒鐘圖片還未成功返回,那么timeout就跑贏了,則進(jìn)入catch,報(bào)出“圖片請(qǐng)求超時(shí)”的信息。運(yùn)行結(jié)果如下:

六、總結(jié)
ES6 Promise的內(nèi)容就這些嗎?是的,能用到的基本就這些。
我怎么還見過done、finally、success、fail等,這些是啥?這些并不在Promise標(biāo)準(zhǔn)中,而是我們自己實(shí)現(xiàn)的語法糖。
本文中所有異步操作均以setTimeout為例子,之所以不使用ajax是為了避免引起混淆,因?yàn)檎勂餫jax,很多人的第一反應(yīng)就是jquery的ajax,而jquery又有自己的Promise實(shí)現(xiàn)。如果你理解了原理,就知道使用setTimeout和使用ajax是一樣的意思。說起jquery,我不得不吐槽一句,jquery的Promise實(shí)現(xiàn)太過垃圾,各種語法糖把人都搞蒙了,我認(rèn)為Promise之所以沒有全面普及和jquery有很大的關(guān)系。后面我們會(huì)細(xì)講jquery。
關(guān)于Promise還有一些內(nèi)容是需要講的,限于篇幅,本文就只作ES6 Promise的講解,接下來還會(huì)有大白話講解系列:
Promise/A+規(guī)范
jquery中的Promise
敬請(qǐng)期待!