Promise 是一個構造函數,它自身擁有all、reject、resolve這幾個眼熟的方法, 原型上有then、catch等一樣熟悉的方法。 因此,在開始一個Promise的時候,先new一個吧:javascript
let p = new Promise((resolve, reject)=> {
setTimeout(()=> {
resolve('執行完成')
}, 1000)
})
複製代碼
Promise是一個構造函數,接受一個回調函數做爲參數,回調函數的參數是resolve
、reject
。分別表示異步操做執行成功後的回調函數和異步操做執行失敗後的回調函數。其實這裏用「成功」和「失敗」來描述並不許確,按照標準來說,resolve
是將Promise的狀態置爲fullfiled,reject
是將Promise的狀態置爲rejected。不過在咱們開始階段能夠先這麼理解,後面再細究概念。前端
在上面的代碼中,咱們執行了一個異步操做,也就是setTimeout,1秒後,輸出「執行完成」,而且調用resolve方法。java
行代碼,會在2秒後輸出「執行完成」。注意!我只是new了一個對象,並無調用它,咱們傳進去的函數就已經執行了,這是須要注意的一個細節。因此咱們用Promise的時候通常是包在一個函數中,在須要的時候去運行這個函數,如:dom
function runAsync() {
let p = new Promise((resolve, reject)=> {
setTimeout(()=> {
console.log('執行完成');
resolve(123);
}, 2000)
})
return p;
}
runAsync()
複製代碼
這時候你應該有個疑問:包裝這麼一個函數有什麼做用?異步
在咱們包裝好的函數最後,會return出Promise對象 p
,也就是說,執行這個函數咱們獲得了一個Promise對象。Promise對象上有then、catch方法,這這個時候就能夠用到它們了,看下面的代碼:函數
runAsync().then((result)=> {
console.log(result);
// 作其餘操做
})
複製代碼
在runAsync()的返回上直接調用then
方法,then
接收一個參數,是函數,而且會拿到咱們在runAsync中調用resolve時傳的的參數。運行這段代碼,會在2秒後輸出「執行完成」,緊接着輸出 「123」 。ui
這個時候你可能已經明白了,原來then
方法和咱們平時寫的回調函數是一個道理,那咱們直接寫回調函數就好了啊,爲何還要寫Promise呢。spa
確實在一些簡單的場景下,回調函數已經夠用,可是在如今前端的大環境和大發展的狀態下,常常會出現回調地獄的狀況,你可能須要在回調函數中,再繼續回調函數,這樣下去就會很恐怖了。Promise就給咱們帶來了更好的解決辦法。code
Promise的優點在於,能夠在then方法中繼續寫Promise對象並返回,而後繼續調用then來進行回調操做。對象
看下面一個例子,多層回調時是怎麼使用的:
function runAsync1() {
var p = new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('執行完成1');
resolve(1);
}, 2000)
})
return p;
}
function runAsync2() {
var p = new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('執行完成2');
resolve(2);
}, 2000)
})
return p;
}
function runAsync3() {
var p = new Promise(function(resolve, reject) {
setTimeout(function(){
console.log('執行完成3');
resolve(3);
}, 2000)
})
return p;
}
runAsync1().then(function(data) {
console.log(data);
return runAsync2();
}).then(function(data) {
console.log(data);
return runAsync3();
}).then(function(data) {
console.log(data);
return '直接返回數據'
}).then(function(data) {
console.log(data);
})
複製代碼
在鏈式操做中,當一個Promise結束後,能夠繼續返回一個新的Promise,在下一個then
方法中繼續接收其返回的resolve
。
在then方法中,你也能夠直接return數據而不是Promise對象,在後面的then中就能夠接收到數據了,看上面例子的最後一個。
說完resolve
,就不得不說reject
,它們都是Promise自身的方法,簡單來講,reject方法返回的是錯誤信息,將Promise的狀態置爲rejected
,上面已經說過。
咱們下面來看看具體的實現:
function getNumber() {
var p = new Promise(function(resolve, reject) {
setTimeout(function(){
var num = Math.ceil(Math.random()*10);
if(num<5) {
resolve(num)
} else {
reject('數字太大了')
}
}, 2000)
});
return p;
}
getNumber()
.then(
function(data) {
console.log('resolve')
console.log(data);
},
function(reason) {
console.log('reject')
console.log(reason);
}
)
複製代碼
咱們建立一個隨機1-10的數,判斷大小,返回不一樣的resolve和reject。
首先咱們能夠在then方法中第二個參數來接收reject返回值。若是是大於5咱們就會打印出數字太大了
。
可是不少人以前都有接觸過Promise,知道還有一個catch
的鏈式操做方法。它也能夠用來接收reject
返回的信息。來看下面的代碼:
getNumber()
.then(function(data) {
console.log('resolve');
console.log(data);
})
.catch(function(reason) {
console.log('reject');
console.log(reason);
})
複製代碼
若是數字大於5就會打印 reject 6
。
若是你在then
中出現了錯誤,也不會中斷程序的運行,會在catch
中打印出錯誤信息:
getNumber()
.then(function(data) {
console.log('resolve');
console.log(data);
console.log(somedata);
})
.catch(function(reason) {
console.log('reject');
console.log(reason); // ReferenceError: somedata is not defined
})
複製代碼