Promise的理解及react中的運用

李群彬發表於2018-03-31

前言

前幾天同事無意間問我對promise的理解,作為一年前端開發的我,雖然專案裡一直有在用,但細細回想promise是什麼、怎麼用的和我對這個的理解,還真不說不出來,所以我週末就好好花了時間對promise進行了淺層的瞭解,如果有說錯的歡迎指點。

一、promise是什麼?為什麼會有promise?

首先,promise是js的抽象非同步處理物件實現非同步程式設計的方案,簡單的說就是解決傳統js執行單執行緒的詬病以及非同步操作的多層級巢狀帶來的麻煩。

Q:資料說promise是個容器,我對這個理解不是很清晰。

我的理解是說,這個容器指promise的非同步操作內容,然後我們這個操作放在這個容器裡面讓他自己執行,不會受外界影響。

然後,promise有三種狀態,分別是:pending、fulfilled、rejected; 當 promise執行resolve是狀態由pending->fulfilled; 當 promise執行reject是狀態由pending->rejected; 狀態一旦改變就不會再變。

avatar

二、基本用法

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請求的運用

未完,待續。

相關文章