js 異步編程方式: Promise船殉,generator/yield,async/await
- 回掉函數(shù)
- js事件監(jiān)聽 和 jquery事件
- 發(fā)布/訂閱
- promise
generator()
- Generator函數(shù)是一個(gè)狀態(tài)機(jī)洽瞬,封裝了多個(gè)內(nèi)部狀態(tài)。
- Generator函數(shù)會返回一個(gè)遍歷器對象俄讹,也就是說帽芽,Generator函數(shù)除了狀態(tài)機(jī),還是一個(gè)遍歷器對象生成函數(shù)殃姓。返回的遍歷器對象袁波,可以依次遍歷Generator函數(shù)內(nèi)部的每一個(gè)狀態(tài)瓦阐。
- Generator函數(shù)可以暫停執(zhí)行的function。
函數(shù)名之前要加星號區(qū)別篷牌,只有調(diào)用next方法時(shí)睡蟋,函數(shù)f才會執(zhí)行
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
// yield是暫停標(biāo)志
}
done屬性的值false,表示遍歷還沒有結(jié)束枷颊。//ture 相反
promise
什么是Promise
Promise最早由社區(qū)提出并實(shí)現(xiàn)戳杀,典型的一些庫有Q,when夭苗, bluebird等信卡;它們的出現(xiàn)是為了更好地解決JavaScript中異步編程的問題,傳統(tǒng)的異步編程最大的特點(diǎn)就是地獄般的回調(diào)嵌套题造,一旦嵌套次數(shù)過多傍菇,就很容易使我們的代碼難以理解和維護(hù)。而Promise則可以讓我們通過鏈?zhǔn)秸{(diào)用的方法去解決回調(diào)嵌套的問題界赔,使我們的代碼更容易理解和維護(hù)丢习,而且Promise還增加了許多有用的特性,讓我們處理異步編程得心應(yīng)手淮悼。
如何創(chuàng)建Promise
ES6給我們提供了一個(gè)原生的構(gòu)造函數(shù)Promise咐低,我們可以看一下這個(gè)構(gòu)造函數(shù):
// 下面的代碼可以直接運(yùn)行在瀏覽器的控制臺中(Chrome瀏覽器)
> typeof Promise
"function" // 可以看出這是一個(gè)構(gòu)造函數(shù)
> Promise
function Promise() { [native code] } // ES6的原生支持
下面我們先來創(chuàng)建一個(gè)promise,下面是一個(gè)簡單的示例:
// 我們先使用ES5的語法
var promise = new Promise(function(resolve, reject) {
var flag = Math.random();
setTimeout(function() {
if(flag) {
resolve('success');
}
else {
reject('fail');
}
}, 1000);
});
console.log(promise); // 在瀏覽器的控制臺運(yùn)行的話袜腥,它返回的是一個(gè)包含了許多屬性的Promise對象见擦;在Node.js環(huán)境中控制臺輸出 Promise { <pending> }。
promise.then(function(result) {
console.log(result);
}, function(err) {
console.log(err);
}); // 1s后這里的輸出可能是fail也可能是success
下面來解釋一下上面的代碼:
因?yàn)镻romise是一個(gè)構(gòu)造函數(shù)瞧挤,所以我們使用了new操作符來創(chuàng)建promise。
構(gòu)造函數(shù)Promise的參數(shù)是一個(gè)函數(shù)(暫時(shí)叫它func)儡湾,這個(gè)函數(shù)(func)有兩個(gè)參數(shù)resolve和reject特恬,它們分別是兩個(gè)函數(shù),這兩個(gè)函數(shù)的作用就是將promise的狀態(tài)從pending(等待)轉(zhuǎn)換為resolved(已解決)或者從pending(等待)轉(zhuǎn)換為rejected(已失斝炷啤)癌刽。
創(chuàng)建后的promise有一些方法,then和catch尝丐。當(dāng)然我們也可以人為的在Promise函數(shù)上添加一些滿足我們自己需求的方法显拜,方便每一個(gè)promise對象使用。
如果我們使用一些ES6的語法的話爹袁,我們上面的代碼會更加簡潔:
let p = new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.5 ? resolve('success') : reject('fail');
}, 1000)
});
console.log(p);
p.then((result) => {
console.log(result);
}, (err) => {
console.log(err);
});
其實(shí)可以這樣理解远荠,Promise函數(shù)體的內(nèi)部包裹著一個(gè)異步的請求或者操作或者函數(shù);然后我們可以在這個(gè)異步的操作完成的時(shí)候使用resolve函數(shù)將我們獲得的結(jié)果傳遞出去失息,或者使用reject函數(shù)將錯(cuò)誤的消息傳遞出去譬淳。
Promise對象的一些方法
Promise對象可以通過使用then方法將上一步返回的結(jié)果獲取過來(不管是resolved還是rejected)档址,可以通過使用catch方法捕獲Promise對象在使用catch之前的異常。
首先來說一下then方法的使用:
let p = new Promise((resolve, reject) => {
let flag = Math.random() > 0.5 ? true : false;
if(flag) {
console.log('使用resolve將promise狀態(tài)從pending變?yōu)閞esolved');
resolve('success');
}
else {
console.log('使用reject將promise狀態(tài)從pending變?yōu)閞ejected');
reject('fail');
}
});
// @1
p.then((result) => {
console.log('接受resolved的結(jié)果');
console.log(result);
}, (err) => {
console.log('捕獲錯(cuò)誤的結(jié)果');
console.log(err);
});
我們可以看到邻梆,then方法可以接受兩個(gè)函數(shù)作為參數(shù)守伸,第一個(gè)函數(shù)是用來處理resolve的結(jié)果,第二個(gè)是可選的浦妄,用來處理reject的結(jié)果尼摹。也就是說,我們在創(chuàng)建p這個(gè)Promise對象的時(shí)候剂娄,通過函數(shù)resolve傳遞出去的結(jié)果可以被p的第一個(gè)then方法中的第一個(gè)函數(shù)捕獲然后作為它的參數(shù)蠢涝。通過函數(shù)reject傳遞出去的結(jié)果可以被p的第一個(gè)then方法中的第二個(gè)函數(shù)捕獲然后作為它的參數(shù)。
當(dāng)然我們還可以在每一個(gè)then方法中創(chuàng)建新的Promise宜咒,然后將這個(gè)Promise對象返回惠赫,之后我們就可以在后面的then方法中繼續(xù)對這個(gè)對象進(jìn)行操作。下面是一個(gè)簡單的例子:
let p1 = new Promise((resolve, reject) => {
let flag = Math.random() > 0.5 ? true : false;
resolve();
});
// @2 使用then方法進(jìn)行鏈?zhǔn)降恼{(diào)用
p1.then(() => {
return 1;
}).then((result) => {
console.log(result);
return 'hello'
}).then((result) => {
console.log(result);
});
// @3 在then方法內(nèi)部可以再次使用異步的操作
p1.then(() => {
console.log('******');
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 1000);
});
return p1;
}).then((result) => {
console.log(result);
});
從上面的代碼中我們可以看到故黑,一旦創(chuàng)建一個(gè)Promise對象之后儿咱,我們就可以使用then方法來進(jìn)行鏈?zhǔn)降恼{(diào)用,而且我們可以把每一次的結(jié)果都返還給下一個(gè)then方法场晶,然后在下一個(gè)then方法中對這個(gè)值進(jìn)行處理混埠。每一個(gè)then方法中都可以再次新創(chuàng)建一個(gè)Promise對象,然后返還給下一個(gè)then方法處理诗轻。
Promise還有另一個(gè)方法catch钳宪,這個(gè)方法其實(shí)是then方法的一種特例,這個(gè)特例就是:
.then(null, rejection)
相當(dāng)于我們不使用then方法的第一個(gè)函數(shù)扳炬,只是用第二個(gè)函數(shù)吏颖;catch函數(shù)比較簡單,就是用來捕獲之前的then方法里面的異常恨樟,我們可以簡單的來看一個(gè)例子:
let p = new Promise((resolve, reject) => {
resolve();
});
p.then(() => {
console.log('progress...');
}).then(() => {
throw new Error('fail');
}).catch((err) => {
console.log(err);
});
上面代碼的輸出結(jié)果如下:
progress...
VM141:9 Error: fail(…)
我們可以使用catch函數(shù)來捕獲整個(gè)then函數(shù)鏈中的異常半醉。
Promise的一些方法
Promise.all方法用來包裝許多個(gè)Promise實(shí)例,然后組成了一個(gè)新的Promise對象劝术,新的Promise對象的狀態(tài)由前面幾個(gè)被包裹的Promise對象的狀態(tài)決定缩多,如果前面的Promise都被resolve了,那么新的Promise的狀態(tài)也是resolve的养晋;只要有一個(gè)Promise被reject了衬吆,那么組成的新的Promise的狀態(tài)也是reject的。
可以看下面一個(gè)例子:
let arr = [1, 2, 3].map(
(value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value);
}, value * 1000);
});
}
);
console.log(arr);
let promises = Promise.all(arr)
.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err);
});
上面的代碼的輸出結(jié)果如下:
[ Promise { <pending> },
Promise { <pending> },
Promise { <pending> } ]
[ 1, 2, 3 ] // 3s后輸出的結(jié)果
Promise.race方法和上面的Promise.all有點(diǎn)類似绳泉,都是包裝許多的Promise對象逊抡,然后組成了一個(gè)新的Promise對象,但是使用Promise.race的含義是:只要包裹的的Promise對象中有一個(gè)的狀態(tài)發(fā)生了改變零酪,那么組成的這個(gè)新的Promise對象的狀態(tài)就是上面那個(gè)率先改變的Promise實(shí)例的狀態(tài)秦忿。
下面是一個(gè)簡單的例子:
let arr = [1, 2, 3].map(
(value) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(value);
}, value * 1000);
});
}
);
console.log(arr);
let promises = Promise.race(arr)
.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err);
});
上面程序的輸出結(jié)果如下:
[ Promise { <pending> },
Promise { <pending> },
Promise { <pending> } ]
1 // 是最先改變狀態(tài)的那個(gè)Promise實(shí)例resolve的值
Promise.resolve方法主要是將一個(gè)值轉(zhuǎn)變?yōu)橐粋€(gè)Promise對象麦射,然后使它具有Promise的一些方法和特性,為了滿足我們一些特殊情況下的要求灯谣。
下面是一個(gè)簡單的例子:
let arr = [null, 0, 'hello',
{ then: function() { console.log(' a thenable obj')}}
];
arr.map((value) => {
return Promise.resolve(value);
});
console.log(arr);
上面的輸出結(jié)果如下:
[ null, 0, 'hello', { then: [Function: then] } ]
a thenable obj // Promise.resolve方法會將具有then方法的對象轉(zhuǎn)換為一個(gè)Promise對象潜秋,然后就立即執(zhí)行then方法。
Promise.reject方法和Promise.resolve方法一樣胎许,只不過通過Promise.reject方法產(chǎn)生的Promise對象的狀態(tài)是rejected的峻呛,下面是一個(gè)示例:
let p = Promise.reject('fail');
p.catch((err) => {
console.log(err);
}); // fail