前言
前幾天同事無意間問我對promise的理解,作為一年前端開發的我,雖然專案裡一直有在用,但細細回想promise是什麼、怎麼用的和我對這個的理解,還真不說不出來,所以我週末就好好花了時間對promise進行了淺層的瞭解,如果有說錯的歡迎指點。
一、promise是什麼?為什麼會有promise?
首先,promise是js的抽象非同步處理物件實現非同步程式設計的方案,簡單的說就是解決傳統js執行單執行緒的詬病以及非同步操作的多層級巢狀帶來的麻煩。
Q:資料說promise是個容器,我對這個理解不是很清晰。
我的理解是說,這個容器指promise的非同步操作內容,然後我們這個操作放在這個容器裡面讓他自己執行,不會受外界影響。
然後,promise有三種狀態,分別是:pending、fulfilled、rejected; 當 promise執行resolve是狀態由pending->fulfilled; 當 promise執行reject是狀態由pending->rejected; 狀態一旦改變就不會再變。
二、基本用法
1、例項
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 非同步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
複製程式碼
Promise物件是一個建構函式,例項後的Promise是一個物件,該建構函式接受一個函式引數,這個函式引數傳入兩個引數(resolve,reject), 這兩個引數是各是一個函式方法; 我們可以根據函式的結果來判斷執行resolve或reject;
2、.then()
promise.then(()=>{
/* resolve 的執行內容 */
},()=>{
/*reject執行的內容*/
}
)
複製程式碼
.then()方法接受兩個函式引數,第一個引數是獲取resolve的內容來執行非同步操作,第二個引數是執行reject,然後執行一個捕獲錯誤的內容,貌似可以獲取程式碼執行錯誤的位置; (我的理解:有then方法的promise才是完整的。)
2.1、第一個函式接受一個來自promise的建構函式resolve傳遞的物件; 3.2、第二個函式會不會promise建構函式的錯誤;
注意:建議是不推薦 .then(()=>{},()=>{/捕獲錯誤/}) 這樣去捕獲錯誤,而是推薦用.catch的方法去捕獲錯誤 .then(()=>{/resolve 內容/}).catch(error){/error捕獲錯誤/}。因為直接在後麵點catch()就能夠捕獲第一次發生錯誤的地方。
運用promise做多層次的回撥 終取到這個節點,但是如果用promise就能夠同步非同步操作去獲取到;
console.log('start');
var promise1 = new Promise((resolve,reject)=>{
setTimeout(resolve('葡萄'),1);
});
promise1.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',蘋果'),1)))
.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',橘子'),1)))
.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',香蕉'),1)))
.then(value=>new Promise((resolve,reject)=>setTimeout(resolve(value+',西瓜'),1)))
.then(value=>{console.log(value)});
console.log('上面是個非同步過程,所以我先出來,後面才是水果');
/*
控制檯列印:
start
上面是個非同步過程,所以我先出來,後面才是水果
葡萄,蘋果,橘子,香蕉,西瓜
*/
複製程式碼
這裡的then都只執行了成功(resolve)方法,來把前面的只拼接起來傳給下個then()方法去接受,下個then的value接受到上面的值繼續new Promise 來執行下一個非同步操作;
3、.all()
Promise.all() 接收一個 promise物件的陣列作為引數,當這個陣列裡的所有promise物件全部變為resolve或reject狀態的時候,它才會去呼叫 .then() 方法。
// `delay`毫秒後執行resolve
function timerPromisefy(delay) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(delay);
}, delay);
});
}
var startDate = Date.now();
// 所有promise變為resolve後程式退出
Promise.all([
timerPromisefy(1),
timerPromisefy(32),
timerPromisefy(64),
timerPromisefy(128)
]).then(function (values) {
console.log(Date.now() - startDate + 'ms');
// 約128ms
console.log(values); // [1,32,64,128]
});
複製程式碼
所以,promise.all,會在所有的引數裡的Promise方法執行完再返回所有資料,以陣列的格式。
4、.race()
Promise.race()的引數跟all一樣是接受一個promise物件陣列,不同的是race(),的結果是隻要有一個promise變個fulfilled或rejected就能夠then()中獲取值,然後其他的Promise物件則會繼續執行。
// `delay`毫秒後執行resolve
function timerPromisefy(delay) {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(delay)
resolve(delay);
}, delay);
});
}
// 任何一個promise變為resolve或reject 的話程式就停止執行
Promise.race([
timerPromisefy(1),
timerPromisefy(32),
timerPromisefy(64),
timerPromisefy(128)
]).then(function (value) {
console.log('then',value); // => 1
});
控制檯
/*
1
32
64
128
then,1
*/
複製程式碼
三、在react中的運用
1、生命週期的運用
前幾天有個需求是要在初次渲染完後獲取頁面的某個節點,但是我用了reactd的生命週期函式始終取到這個節點,但是如果用promise就能夠同步非同步操作去獲取到;
componentWillMount() {
let P = new Promise((resolve, reject)=>{
console.log('new success')
console.log('promiseNew',document.getElementById('text'))
resolve('8888');
})
P.then((value)=>{
console.log('then','obj',document.getElementById('text'));
})
.catch((error)=>{
console.log('it is error',error)
})
}
componentDidMount(){
this.setState({isFind:true})
console.log('DidMount',document.getElementById("text"))
}
render() {
return (
<div>
{this.state.isFind ? (<Divider id="text">this is PromiseClick</Divider>) : null}
</div>
);
}
/*
控制檯列印內容:
new success
promiseNew null
DidMount null
then obj <div class="ant-divider ant-divider-horizontal ant-divider-with-text" id="text">…</div>
*/
複製程式碼
所以,我的認為是在react的生命週期函式裡去執行promise的非同步操作,相當於頁面載入完再去執行的操作;
2、結合ajax請求的運用
未完,待續。