js對於異步操作有三個解決方案,分別是Promise,generator,async/await.
下面分別說說這三種方案的一些基礎.
Promise
promise對象用於表示一個異步操作的最終狀態,Promise在回調代碼和將要執行這個任務的異步代碼之間提供了一種可靠的中間機制來管理回調。
//構造函數,回調函數是同步的回調
new Promise(function(resolve,reject){
....//異步操作
})
Promise的實例對象有三個狀態
-
pending: 初始狀態,既不是成功,也不是失敗狀態。
-
fulfilled: 意味着操作成功完成。
-
rejected: 意味着操作失敗
resolve和reject分別是兩個函數,當在回調中調用時,會改變promise實例的狀態,resolve改變狀態爲成功,reject爲失敗.
then
Promise.prototype.then()
當promise對象的狀態發生改變時,綁定在其身上的then方法就會被調用。
then方法包含兩個參數:onfulfilled函數 和 onrejected函數,它們都是 Function
類型。當Promise狀態爲fulfilled時,調用 then 的 onfulfilled 方法,當Promise狀態爲rejected時,調用 then 的 onrejected 方法, 所以在異步操作的完成和綁定處理方法之間不存在競爭,then() 方法返回一個 Promise對象.
返回值
then方法返回一個新的Promise,而它的行爲與then中的回調函數的返回值有關:
-
如果then中的回調函數返回一個值,那麼then返回的Promise將會成爲接受狀態,並且將返回的值作爲接受狀態的回調函數的參數值。
-
如果then中的回調函數拋出一個錯誤,那麼then返回的Promise將會成爲拒絕狀態,並且將拋出的錯誤作爲拒絕狀態的回調函數的參數值。
-
如果then中的回調函數返回一個已經是接受狀態的Promise,那麼then返回的Promise也會成爲接受狀態,並且將那個Promise的接受狀態的回調函數的參數值作爲該被返回的Promise的接受狀態回調函數的參數值。
-
如果then中的回調函數返回一個已經是拒絕狀態的Promise,那麼then返回的Promise也會成爲拒絕狀態,並且將那個Promise的拒絕狀態的回調函數的參數值作爲該被返回的Promise的拒絕狀態回調函數的參數值。
-
如果then中的回調函數返回一個未定狀態(pending)的Promise,那麼then返回Promise的狀態也是未定的,並且它的終態與那個Promise的終態相同;同時,它變爲終態時調用的回調函數參數與那個Promise變爲終態時的回調函數的參數是相同的。
catch
catch() 方法返回一個Promise,並且處理拒絕的情況。
Promise.prototype.catch()
事實上,catch方法相當於then方法的第二個參數方法,觸發拒絕狀態.
注意,
如果調用 then的 Promise 的狀態(fulfillment 或 rejection)發生改變,但是 then 中並沒有關於這種狀態的回調函數,那麼 then 將創建一個沒有經過回調函數處理的新 Promise 對象,這個新 Promise 只是簡單地接受調用這個 then 的原 Promise 的終態作爲它的終態。所以在鏈式上,最終會執行到catch上.
//鏈式示例
new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("1");
resolve();
}, 1000);
}).then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("2");
// resolve();
reject();
}, 1000);
});
}).then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("3");
resolve();
}, 1000);
});
}).then(function () {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log("4");
resolve();
}, 1000);
});
}).catch(function(){
console.log("catch");
})
genarator
symbol
新的一種基礎數據類型symbol,表示獨一無二的值.
它通常作爲對象的屬性鍵,內置對象普遍存在該值.
// 一般用法,它並不是構造器,不能通過new,會報錯.
let sym = Symbol();
// 在對象中表現形式,要用[]包裹,不然會被認爲是string.
var obj = {
[Symbol()]:"value";
}
該屬性是匿名,所以不可枚舉,只能通過.getOwnPropertySymbols()返回的數組.
// 想要獲得兩個相同的Symbol,得通過.for()
Symbol("asd") === Symbol("asd") // false
Symbol.for("asd") === Symbol.for("asd") // true
Iterator
迭代器,存在於特定幾種可枚舉的數據類型中.
// 一般用以下這種形式的鍵保存了迭代器函數.
// arr[Symbol.iterator]
aarr[Symbol.iterator]( ).next( ) //遍歷下一個,返回value和done,value表示值,done表示是否可以繼續遍歷下一個.
//for...of循環遍歷就是基於此,必須該數據類型有迭代器.
回到generator
//表現形式
function* test(){
yield 1; //任務1
yield 2; //任務2
yield 3; //任務3
yield 4 ; //任務4
}
// 調用該方法會返回一個含有迭代對象的對象.
var obj = text();
obj.next(); //調用該方法時,每次到一個yield處停止.
async/await(最優)
在函數前加async,就形成了函數
async function test (){
// 等待狀態改變,自動執行到下一個wait處
var flag = await new Promise((resolve,reject)=>{
setTimeout(function(){
// 狀態改變
resolve(data); //這裏面的值傳遞給flag
},1000)
})
//通過flag傳遞數據
flag = await new Promise((resolve,reject)=>{
setTimeout(function(flag){
// 狀態改變
resolve(flag);
},1000,flag)
})
}
test().catch(function(err){
//處理異常
});