很久沒寫博客了......看了很多關於Promise的文章,但是感覺也不是很理解,沒辦法去就看視頻了。偶然發現慕課裏有個關於Promise的視頻,然後今天看了前兩章,順便整理了下筆記,記錄下吧~
Promise
是什麼?
-
用於異步計算。
-
可以將異步操作隊列化,按照期望的順序執行,返回符合預期的結果。
-
可以在對象之間傳遞和操作Promise,幫助我們處理隊列。
產生的原因
-
JavaScript包含大量的異步操作(AB工作的完成順序,和交付他們時間順序無關)
-
異步操作的常見語法
-
事件偵聽和響應
-
回調
-
-
常見異步事件(瀏覽器中的JavaScript)
-
異步操作以事件爲主
-
回調主要出現在Ajax和File API
-
-
Node.js是無阻塞高併發、依賴大量回調函數
異步回調的問題
-
嵌套層次很深,容易陷入回調地獄,使得代碼難以維護。
-
無法正常使用return和throw。
-
無法正常檢索堆棧信息。
-
多個回調之間難以建立聯繫。
ps:
-
因爲異步回調函數處於新的棧中,在此棧中無法獲取之前的棧的信息,之前的棧也無法獲取此棧中的錯誤,因此try和catch是無法生效的。
-
因爲無法判斷異步執行順序,只能在外層作用域聲明大量的變量供內層作用域使用,導致這些變量有可能會被其他函數訪問和修改,從而導致錯誤。
Promise詳解
創建過程:
-
初始化Promise實例。
-
在實例中傳入參數,該參數是一個函數(執行器)。
-
執行器擁有兩個參數:resolve、reject。
-
成功調用resolve方法,失敗調用reject方法。不同的方法執行完會改變Promise實例的狀態。
-
執行then方法中對應的函數。
new Promise(
/* 執行器 executor */
function(resolve, reject) {
// 一段耗時很長的異步操作
resolve(); // 數據處理完成
reject(); // 數據處理出錯
}
)
.then(function A() {
// 成功,下一步
}, function B() {
// 失敗,做相應處理
});
理解:
-
Promise是一個代理對象,它和原先要進行的操作並無關係。
-
它通過引入的一個回調,避免更多的回調。
-
Promise狀態發生改變,就會觸發.then()裏的響應函數處理後續步驟。
-
Promise狀態一經改變,不會再變。
-
Promise實例一經創建,執行器立即執行。
Promise的三個狀態
-
pending【待定】初始狀態 —— 實例化
-
fulfilled【實現】操作成功 —— 調用resolve
-
rejected【被否決】操作失敗 —— 調用reject
簡單範例
定時執行
console.log('here we go');
new Promise( resolve => {
setTimeout( () => {
resolve('hello');
},2000);
})
.then( value => {
console.log(value + ' world');
})
//輸出結果
// here we go
/*
Promise {
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: undefined
}
*/
// 兩秒後
// hello world
執行順序:先輸出‘here we go’,接着執行定時器,兩秒後將‘hello’傳給.then()函數,輸出‘hello, world'
兩步執行(常用)
console.log('here we go');
new Promise( resolve => {
setTimeout( () => {
resolve('hello');
}, 2000);
})
.then ( value => {
console.log( value );
return new Promise( resolve => {
setTimeout( () => {
resolve('world');
}, 2000);
});
})
.then ( value => {
console.log( value + ' world');
});
//輸出結果
// here we go
/*
Promise {
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: undefined
}
*/
// 兩秒後
// hello
// 兩秒後
// world world
執行順序:
先輸出‘here we go',接着進入執行器,兩秒後將'hello’傳給第一個.then()函數;
第一個.then()函數輸出‘hello',返回一個新的Promise;
新的Promise中開始執行器,兩秒後將’world'傳給‘第二個then函數;
第二個.then()函數輸出’world world'。
對已完成的Promise執行.then()
console.log('start');
let promise = new Promise( resolve => {
setTimeout( () => {
console.log('the promise fulfilled');
resolve('hello, world');
}, 1000);
});
setTimeout( () => {
promise.then( value => {
console.log(value);
})
}, 3000)
//輸出結果
// start
/*
Promise {
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: undefined
}
*/
// the promise fulfilled
// 1秒後
// 兩秒後
// hello, world
執行順序:先輸出‘start’,接着兩個定時器同時執行,一秒後輸出'the promise fulfilled',並將‘hello, world'傳出;再過兩秒,執行.then(),輸出’hello, world'。
promise隊列的重要特性
在任何地方生成了一個promise隊列之後,我們可以把它作爲一個變量進行牀底,如果我們的操作是隊列的狀態,即先進先出的狀態,就可以在後面追加任意多的.then(),不管之前的隊列是完成還是沒有完成,隊列都會按照固定的順序完成。(下個例子更形象)
在.then()函數裏面不返回新的Promise(並不影響.then()的執行)
console.log('here we go');
new Promise( resolve => {
setTimeout( () => {
resolve('hello');
}, 2000);
})
.then( value => {
console.log(value);
console.log('everyone');
(function() {
return new Promise( resolve => {
setTimeout( () => {
console.log('Mr.Laurence');
resolve('Merry Xmas');
}, 2000);
});
}());
return false;
})
.then( value => {
console.log( value + ' world');
})
//輸出結果
// here we go
/*
Promise {
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: undefined
}
*/
// 兩秒後
// hello
// everyone
// false world
// 兩秒後
// Mr.Laurence
執行順序:
輸出‘here we go',進入Promise實例中,兩秒後將’hello‘傳給第一個.then();
第一個.then()輸出’hello',接着輸出‘everyone',接着執行立即執行函數。在此同時第一個.then()返回false,即將false傳給第二個.then();
第二個.then()輸出’false world';(如果註釋掉return false,則輸出'undefined world',可見返回結果不影響Promise繼續往下執行)
在第一個.then()返回false後的兩秒,輸出'Mr.Lanrence'。
.then()
-
.then()接受兩個函數作爲參數,分別代表fulfilled和rejected
-
.then()返回一個新的Promise實例,所以它可以鏈式調用
-
當前面的Promise狀態改變時,.then()根據其最終狀態,選擇特定的狀態響應函數執行
-
狀態響應函數可以返回新的Promise,或者其他值
-
如果返回新的Promise,那麼下一級.then()會在新Promise狀態改變之後執行
-
如果返回的是其他任何值,則會立即執行下一級.then()
console.log('start');
new Promise(resolve => {
console.log('Step 1');
setTimeout(() => {
resolve(100);
}, 1000);
})
.then(value => {
return new Promise(resolve => {
console.log('Step 1-1');
setTimeout(() => {
resolve(110);
}, 1000);
})
})
.then(value => {
console.log('Step 1-2');
return value;
})
.then(value => {
console.log('Step 1-3');
return value;
})
.then(value => {
console.log(value);
console.log('Step 2');
})
// 輸出
// start
// Step 1
// 一秒後
// Step 1-1
// Step 1-2
// Step 1-3
// 110
// Step 2