我們 學習一個新的特性時,我習慣先了解他是什麼, 有什麼用
在 w3c中 可知 Promise 是 抽象異步處理對象以及對其進行各種操作的組件 . 他 多用於 處理回調地獄 . 什麼是回調地獄呢? 即 嵌套多個回調 如果 有多個回調互相嵌套 則 會難以調試與 理解 增大代碼維護的難度與可讀性
使用 promise 就能解決這個問題 , promise 可以是一個佔位符,表示異步操作的執行結果, 函數可以返回一個promise 而不 是 傳遞一個回調
promise 都會有一個 短暫的生命週期
有兩種狀態
初始的掛起未決狀態 --> 異步未結束
已決的狀態 ---> 異步操作結束
處於 已決轉態 會有兩種情況
1 已經成功完成的異步操作
2 可能是一個錯誤或者其他的原因導致了 異步的操作沒成功
此時 promise中有個 [ [PromiseState]] 屬性 會被設置 爲 pending fulfilled 或者 rejected , 以反映 promise 的狀態處於 哪一步 . 但這個屬性 並不在 promise 對象上面 暴露. 因此 無法 判斷 他處於那種狀態
但此時其 提供了
then() 方法
他在所有的promise 上都存在. 並且接受兩個參數 .
第一個 參數 是promise 被完成時 調用的 函數 , 異步操作的結果數據
都會傳入 完成函數
第二個函數 則是 promise 被拒絕的時調用的函數, 也會將失敗的參數數據
這兩個參數是可選的 可以自由的監聽 完成 和失敗的處理函數
catch 方法
Promise有catch()方法,等同於只傳遞拒絕處理函數給then()方法:
用處
比如 Vue 發起axios 的請求時 正常來說異步 返回的是 一個 回調函數. 但此時 使用 promise 直接返回一個 axios.get或者 axios.post 讓這個 promise 對象 (axios是promise對象 )自己 進行 成功 ( .then() ) 之後的 處理 或者失敗(.catch() ) 的提示
他人總結:
Promise 具有三種狀態:掛起、已完成、已拒絕。一個 Promise 起始於掛起態,並在成功時轉爲完成態,或在失敗時轉爲拒絕態。 then() 方法允許你綁定完成處理函數與拒絕處理函數,而 catch() 方法則只允許你綁定拒絕處理函數;
能夠將多個Promise串聯起來組成Promise鏈,並且能夠在中間傳遞值,甚至是傳遞Promise對象。 then() 的調用都創建並返回了一個新的 Promise ,只有在前一個 Promise 被決議過,新 Promise 也會被決議。 同時也可以使用Promise.all()和Promise.race()方法來管理多個Promise
例子
/**
* promise 對象是一個構造函數, 用來生成 promise 對象
*
* resolve 將 promise 對象的狀態從 未完成=> 轉變成 成功, 並且在 異步調用成功之後, 將成功之後的結果 傳遞出去
* reject 將 promise 對象的狀態 從 未完成=> 轉變成 失敗, 並且在 異步調用失敗的錯誤作爲參數 傳遞出去
*
* promise 實例生成之後 可以分別指定 resolve 狀態和 reject 狀態的 回調函數
*/
// promise
var promise = new Promise((resolve, reject) => {
if (true) {
resolve();
} else {
reject();
}
})
// 例子 一
function timeFun (ms) {
return new Promise ((resolve, reject) => {
setTimeout(resolve, ms, 'done');
})
}
timeFun(100).then(resolve => {
console.log(resolve) // done
})
// 例子二 // promise 一旦建立就會立即執行
const promiseTwo = new Promise((resolve, reject) => {
console.log("我是第一個輸出的");
resolve();
})
promiseTwo.then(res => {
console.log('我是第三個輸出的');
})
console.log('我是第二個輸出的')
/**
* 輸出結果
* promise.js:31 我是第一個輸出的
promise.js:39 我是第二個輸出的
promise.js:36 我是第三個輸出的
promise.js:26 done
promise 新建之後會立即執行 , 首先輸出第一 , promise 裏面的 resolve 是異步方法, 所以先執行 所有同步再執行異步, 此時 會先輸出 第二,
然後再輸出 第三 , 100 之後 會再執行 done
*/
// 例子三 promise 實現操作 Ajax 操作
let promiseAjax = function (url) {
let promise = new Promise ((resolve, reject) => {
// 新建一個 對象
var xhr = new XMLHttpRequest();
// 請求方式
xhr.open('GET', url);
// 狀態請求改變的回調
xhr.onreadystatechange = handler;
// 返回數據格式
xhr.responseType = 'json',
xhr.setRequestHeader('Accept', 'application/json');
xhr.send();
function handler() {
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText))
}
}
})
return promise
}
var url = 'http://httpbin.org/get';
promiseAjax(url).then(res => {
console.log('res', res)
}).catch(error => {
console.log('error',error)
})
// 輸出 res null promise 中的 resolve 跟 reject 都 會帶有參數回傳 ,
//一個成功之後的參數, 一個失敗之後的, 成功的也可能是 一個 promise 實例, 如 Vue 中的 axios 實例
/**
* 要理解 promise 中的 then 方法, 該方法作用是在 Promise 實例狀態改變時的回調函數 , then 方法的第一個參數 是 resolve(成功的) 狀態的回調,
* 第二個參數 是 reject(失敗的) 的 狀態的回調
* {
* 但是不推薦使用第二個參數-> 推薦使用 catch 進行捕獲錯誤, 原因-> 因爲promise的 狀態一旦改變,就永久保持該狀態, 使用 then 第二個參數識別錯誤,錯誤並不會一直傳遞,
* 但Promise對象的錯誤具有傳遞性質,它會一直往下傳遞,直到被catch捕獲到爲止。
* },
* 還有需要注意的是 then 方法返回的 還是一個 promise 對象.
* 所以我們可以使用 鏈式 寫法, then 後面再跟 then 方法 (vue 的 axios 使用)
*
* 如下
*
*/
// then 鏈式寫法
promiseAjax(url).then(res => {
console.log(1,res)
return res
}).then(val => {
console.log(2, val) // 返回的是 與上面一直的結果 輸出: 1 null 2 null
})
// 錯誤捕獲案例
// 不推薦 的寫法
var p6 = new Promise((resolve, reject) => { });
p6.then((data) => {
// success
}, (error)=>{
// error
});
// 推薦 的寫法
p6.then((data) => {
// success
}).catch((error) => {
// error
})
這篇文章解析的更爲 詳細易懂.
https://www.jianshu.com/p/063f7e490e9a