Promise
是什麼?通俗來說,Promise
就是一個用於保存異步操做的容器。當一個異步操做完成後,它要麼保存了值,要麼保保存了錯誤的信息。Promise
基本上就是「承諾」你它會給你一個異步操做的結果。git
這個對象分爲三個階段:數據庫
pending
階段,建立promise
對象時,處於掛起狀態,關聯某個異步操做。Fullfilled
階段,表示promise
有結果將被履行,異步操做成功完成,有結果了。Rejected
階段,表示異步操做過程當中出現問題,被拒絕了,獲得錯誤值。首先建立一個Promise
對象,這個構造函數須要一個參數,這個參數是一個須要兩個參數的函數。分別是resolve
和reject
兩個參數的匿名函數編程
const p = new Promise((resolve,reject) => {
//成功後執行的函數
resolve('hello')
//失敗後執行的函數
reject(new Error('message'))
})
複製代碼
咱們日常查詢一個數據庫,請求一個網絡服務或者設置一個延時執行的程序都會用到異步操做,而promise
對象也就很是適合這些場合使用。數組
由於使用了promise
,因此後面必定會給咱們一個異步操做的結果,不管是成功的函數失敗的。因此咱們須要將值返回給promise
的使用者,咱們就用上面的resolve
和reject
參數來實現。promise
假設上面的異步操做完成了,執行的結果就是「hello」。在現實編程中,這個「hello」也能夠是一個從數據庫中讀取的信息,這就是異步操做的結果。如今咱們須要兌現了,由於後續可能使用了p
對象。看它有兩個方法。 bash
catch
用於獲取任何的報錯,
then
用來獲取異步操做成功的返回值,咱們調用
then
,而後傳入一個函數。這裏咱們傳入
result
,就是裏面的
resolve
函數。
const p = new Promise((resolve, reject) => {
//成功後執行的函數
resolve("hello");
//失敗後執行的函數
reject(new Error("message"));
});
p.then(result => console.log("result", result));
複製代碼
打開控制檯,運行promise.js
。 網絡
hello
,很好,再次改造下添加一個定時器,實現異步操做。
const p = new Promise((resolve, reject) => {
//成功後執行的函數
setTimeout(() => resolve("hello"), 2000);
//失敗後執行的函數
// reject(new Error("message"));
});
p.then(result => console.log("result", result));
複製代碼
再次運行,能夠看到間隔2秒後返回告終果。 異步
error
返回給調用者,最後連接上
catch
,當遇到什麼問題的時候能夠了解到具體的錯誤是什麼。
const p = new Promise((resolve, reject) => {
//成功後執行的函數
setTimeout(() => {
// resolve("hello");
reject(new Error("message"));
}, 2000);
});
p.then(result => console.log("result", result)).catch(err =>
console.log("Error", err.message)
);
複製代碼
如今總結一下,Promise
是一個對象,用於保存異步操做的任何結果,當咱們建立對象的時候進入了掛起的狀態。上面的代碼就是它開始處理一個異步操做,這個操做有可能成功也可能失敗。async
若是成功了,咱們就說承諾「解決」了,或者是被履行了。Promise
的狀態由掛起轉爲解決或者履行,咱們就用resolve
函數返回結果給調用者。函數
若是異步操做失敗了,Promise
的狀態由掛起轉爲拒絕,咱們就用reject
函數返回一個錯誤給調用者。
這就是如何建立一個Promise
,而後是如何使用它。咱們使用then
來獲得結果,catch
來捕捉錯誤對象。有一點須要提到的是若是在任何地方用到了異步的回調,都應該讓函數返回一個Promise
。
Promise
並行操做是什麼?有時咱們可能想要並行的處理幾個異步請求,當它們所有結束後再作點什麼。好比可能同時請求兩個或以上網站的API
,當全部的請求都完畢的時候就能夠返回什麼給客戶端了。
首先建立兩個Promise
對象,這裏咱們須要返回結果,不要被拒絕,因此就一個參數。
const p1 = new Promise(resolve => {
setTimeout(() => {
console.log("異步操做1");
resolve(1);
}, 2000);
});
const p2 = new Promise(resolve => {
setTimeout(() => {
console.log("異步操做2");
resolve(2);
}, 2000);
});
複製代碼
如今我想同時處理這兩個請求,當它們都完成的時候咱們再作些什麼。這裏調用Promise.all()
,這是另外一個Promise
類的靜態方法,而不是Promise
對象的實例方法。而後傳入一個Promise
對象的數組,這裏是p1
,p2
,將會返回一個新的Promise
。它的履行取決於全部包含Promise
對象所有履行。先調用這個Promise
,而後調用then
,將結果顯示在控制檯。
Promise.all([p1, p2]).then(result => console.log(result));
複製代碼
若是其中一個Promise
對象失敗了呢?咱們修改第一個Promise
,讓它有reject
參數
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("異步操做1");
reject(new Error("出現錯誤了"));
}, 2000);
});
const p2 = new Promise(resolve => {
setTimeout(() => {
console.log("異步操做2");
resolve(2);
}, 2000);
});
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(err => console.log("Error", err.message));
複製代碼
再次運行查看,只要其中一個Promise
出錯了,所有Promise
的最終返回值都會被拒絕。
Promise
實現了就當即進行某些操做,而不是等到全部所有履行。這樣的話可使用
race
方法取代
all
。
const p1 = new Promise(resolve => {
setTimeout(() => {
console.log("異步操做1");
resolve(1);
}, 2000);
});
const p2 = new Promise(resolve => {
setTimeout(() => {
console.log("異步操做2");
resolve(2);
}, 2000);
});
Promise.race([p1, p2])
.then(result => console.log(result))
.catch(err => console.log("Error", err.message));
複製代碼
Promise
履行,就能夠拿到結果。
Async/Await
是什麼?在如今的JavaScript
中有個新特性,async
和await
,這可讓你寫同步代碼同樣寫異步代碼。
function getUser(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("讀取id中...");
resolve({
id: id,
gitHubUsername: "mosh"
});
}, 2000);
});
}
function getRepositories(username) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("獲取用戶信息中...");
resolve(["repo1", "repo2", "repo3"]);
}, 2000);
});
}
function getCommits(text) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("獲取內容中...");
resolve(["hello"]);
}, 2000);
});
}
複製代碼
要注意的是使用Async/Await
,在Promise
中咱們使用try-catch
塊來捕捉異常,它沒有catch
方法。在這個函數中,咱們將全部的異步操做代碼包含到try
塊中,而後是catch
塊。捕捉到的是err
對象。若是有異常,catch
塊的代碼就執行。
async function displayCommits() {
try {
const user = await getUser(1);
const repos = await getRepositories(user.gitHubUsername);
const commits = await getCommits(repos[0]);
console.log(commits);
} catch (err) {
console.log("Error", err.message);
}
}
displayCommits();
複製代碼
仍是在控制檯執行: