怎樣做單頁銷售網(wǎng)站軟文范例大全100字
ES6 Promise 對象
一、概述
是異步編程的一種解決方案。
從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。
Promise 狀態(tài)
狀態(tài)的特點
Promise 異步操作有三種狀態(tài):pending(進行中)、fulfilled(已成功)和 rejected(已失敗)。除了異步操作的結(jié)果,任何其他操作都無法改變這個狀態(tài)。
Promise 對象只有:從 pending 變?yōu)?fulfilled 和從 pending 變?yōu)?rejected 的狀態(tài)改變。只要處于 fulfilled 和 rejected ,狀態(tài)就不會再變了即 resolved(已定型)。
const p1 = new Promise(function(resolve,reject){
resolve(‘success1’);
resolve(‘success2’);
});
const p2 = new Promise(function(resolve,reject){
resolve(‘success3’);
reject(‘reject’);
});
p1.then(function(value){
console.log(value); // success1
});
p2.then(function(value){
console.log(value); // success3
});
狀態(tài)的缺點
無法取消 Promise ,一旦新建它就會立即執(zhí)行,無法中途取消。
如果不設(shè)置回調(diào)函數(shù),Promise 內(nèi)部拋出的錯誤,不會反應到外部。
當處于 pending 狀態(tài)時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。
二、基本用法
ES6 規(guī)定,Promise對象是一個構(gòu)造函數(shù),用來生成Promise實例。
下面代碼創(chuàng)造了一個Promise實例。
const promise = new Promise(function(resolve, reject) {
// … some code
if (/ 異步操作成功 /){
resolve(value);
} else {
reject(error);
}
});
Promise構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是resolve和reject。它們是兩個函數(shù),由 JavaScript 引擎提供,不用自己部署。
resolve函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤俺晒Α?#xff08;即從 pending 變?yōu)?resolved),在異步操作成功時調(diào)用,并將異步操作的結(jié)果,作為參數(shù)傳遞出去;reject函數(shù)的作用是,將Promise對象的狀態(tài)從“未完成”變?yōu)椤笆 ?#xff08;即從 pending 變?yōu)?rejected),在異步操作失敗時調(diào)用,并將異步操作報出的錯誤,作為參數(shù)傳遞出去。
Promise實例生成以后,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
then方法可以接受兩個回調(diào)函數(shù)作為參數(shù)。第一個回調(diào)函數(shù)是Promise對象的狀態(tài)變?yōu)閞esolved時調(diào)用,第二個回調(diào)函數(shù)是Promise對象的狀態(tài)變?yōu)閞ejected時調(diào)用。這兩個函數(shù)都是可選的,不一定要提供。它們都接受Promise對象傳出的值作為參數(shù)。
下面是一個Promise對象的簡單例子。
<button @click="addReturnPromise">練習方法返回一個Promise實例</button>
timeout(ms){return new Promise((resolve, reject) => {setTimeout(resolve, ms, "done");});},addReturnPromise() {this.timeout(1000).then((value) => {console.log(value);})},
timeout方法返回一個Promise實例,表示一段時間以后才會發(fā)生的結(jié)果。過了指定的時間(ms參數(shù))以后,Promise實例的狀態(tài)變?yōu)閞esolved,就會觸發(fā)then方法綁定的回調(diào)函數(shù)。
Promise 新建后就會立即執(zhí)行。
<button @click="addPromiseSort">練習執(zhí)行順序相關(guān)</button>
addPromiseSort() {let promise = new Promise(function (resolve, reject) {console.log("Promise");resolve();});promise.then(function () {console.log("resolved.");});console.log("Hi!");},
上面代碼中,Promise 新建后立即執(zhí)行,所以首先輸出的是Promise。然后,then方法指定的回調(diào)函數(shù),將在當前腳本所有同步任務執(zhí)行完才會執(zhí)行,所以resolved最后輸出。
下面是一個用Promise對象實現(xiàn)的 Ajax 操作的例子。
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open(“GET”, url);
client.onreadystatechange = handler;
client.responseType = “json”;
client.setRequestHeader(“Accept”, “application/json”);
client.send();
});
return promise;
};
getJSON(“/posts.json”).then(function(json) {
console.log('Contents: ’ + json);
}, function(error) {
console.error(‘出錯了’, error);
});
如果調(diào)用resolve函數(shù)和reject函數(shù)時帶有參數(shù),那么它們的參數(shù)會被傳遞給回調(diào)函數(shù)。reject函數(shù)的參數(shù)通常是Error對象的實例,表示拋出的錯誤;resolve函數(shù)的參數(shù)除了正常的值以外,還可能是另一個 Promise 實例,比如像下面這樣。
<button @click="addPPromise">練習resolve函數(shù)的參數(shù)除了正常的值以外,還可能是另一個 Promise 實例</button>
addPPromise() {var p1 = new Promise(function (resolve, reject) {// resolve("11");reject("xx");});var p2 = new Promise(function (resolve, reject) {resolve(p1);});console.log(p2);},
addPPromise() {var p1 = new Promise(function (resolve, reject) {resolve("11");// reject("xx");});var p2 = new Promise(function (resolve, reject) {resolve(p1);});console.log(p2);},
注意,這時p1的狀態(tài)就會傳遞給p2,也就是說,p1的狀態(tài)決定了p2的狀態(tài)。如果p1的狀態(tài)是pending,那么p2的回調(diào)函數(shù)就會等待p1的狀態(tài)改變;如果p1的狀態(tài)已經(jīng)是resolved或者rejected,那么p2的回調(diào)函數(shù)將會立刻執(zhí)行。
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error(‘fail’)), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
// Error: fail
上面代碼中,p1是一個 Promise,3 秒之后變?yōu)閞ejected。p2的狀態(tài)在 1 秒之后改變,resolve方法返回的是p1。由于p2返回的是另一個 Promise,導致p2自己的狀態(tài)無效了,由p1的狀態(tài)決定p2的狀態(tài)。所以,后面的then語句都變成針對后者(p1)。又過了 2 秒,p1變?yōu)閞ejected,導致觸發(fā)catch方法指定的回調(diào)函數(shù)。
注意,調(diào)用resolve或reject并不會終結(jié) Promise 的參數(shù)函數(shù)的執(zhí)行。
new Promise((resolve, reject) => {
resolve(1);
console.log(2);
}).then(r => {
console.log?;
});
// 2
// 1
上面代碼中,調(diào)用resolve(1)以后,后面的console.log(2)還是會執(zhí)行,并且會首先打印出來。這是因為立即 resolved 的 Promise 是在本輪事件循環(huán)的末尾執(zhí)行,總是晚于本輪循環(huán)的同步任務。
一般來說,調(diào)用resolve或reject以后,Promise 的使命就完成了,后繼操作應該放到then方法里面,而不應該直接寫在resolve或reject的后面。所以,最好在它們前面加上return語句,這樣就不會有意外。
new Promise((resolve, reject) => {
return resolve(1);
// 后面的語句不會執(zhí)行
console.log(2);
})
三、Promise.all方法,Promise.race方法
Promise.all 方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。
var p = Promise.all([p1,p2,p3]);
Promise.all 方法接受一個數(shù)組作為參數(shù),p1、p2 都是 Promise 對象的實例。(Promise.all 方法的參數(shù)不一定是數(shù)組,但是必須具有 iterator 接口,且返回的每個成員都是 Promise 實例。)
p 的狀態(tài)由 p1、p2 決定,分成兩種情況。
(1)只有p1、p2、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會變成fulfilled,此時p1、p2、p3的返回值組成一個數(shù)組,傳遞給p的回調(diào)函數(shù)。
(2)只要p1、p2、p3之中有一個被rejected,p的狀態(tài)就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調(diào)函數(shù)。
<button @click="addPromiseAll">練習Promise.all</button>
addPromiseAll() {console.log("addPromiseAll");var p1 = new Promise(function (resolve, reject) {resolve("66");// reject("44");});var p2 = new Promise(function (resolve, reject) {resolve("55");});var p = Promise.all([p1, p2]);console.log(p);p.then(function (value) {console.log("value", value);}).catch(function (reason) {console.log("reason", reason);});},
<button @click="addPromiseAll">練習Promise.all</button>
addPromiseAll() {console.log("addPromiseAll");var p1 = new Promise(function (resolve, reject) {// resolve("66");reject("44");});var p2 = new Promise(function (resolve, reject) {resolve("55");});var p = Promise.all([p1, p2]);console.log(p);p.then(function (value) {console.log("value", value);}).catch(function (reason) {console.log("reason", reason);});},
Promise.race 方法同樣是將多個 Promise 實例,包裝成一個新的 Promise 實例。
var p = Promise.race([p1,p2,p3]);
只要p1、p2、p3之中有一個實例率先改變狀態(tài),p的狀態(tài)就跟著改變。那個率先改變的Promise實例的返回值,就傳遞給p的返回值。
如果Promise.all方法和Promise.race方法的參數(shù),不是Promise實例,就會先調(diào)用下面講到的Promise.resolve方法,將參數(shù)轉(zhuǎn)為Promise實例,再進一步處理。
<button @click="addPromiseRace">練習Promise.race</button>
addPromiseRace() {var p1 = new Promise(function (resolve, reject) {resolve("11");// reject("xx");});var p2 = new Promise(function (resolve, reject) {resolve("22");});var p3 = new Promise(function (resolve, reject) {resolve("33");});var p = Promise.race([p1, p2]);console.log(p);p.then(function (value) {console.log("value", value);}).catch(function (reason) {console.log("reason", reason);});},
<button @click="addPromiseRace">練習Promise.race</button>
addPromiseRace() {var p1 = new Promise(function (resolve, reject) {// resolve("11");reject("xx");});var p2 = new Promise(function (resolve, reject) {resolve("22");});var p3 = new Promise(function (resolve, reject) {resolve("33");});var p = Promise.race([p1, p2]);console.log(p);p.then(function (value) {console.log("value", value);}).catch(function (reason) {console.log("reason", reason);});},