深刻理解Promise/ajax

Promise 對象特色

  1. 對象的狀態不受外界影響。 Promise對象表明一個異步操做, 有三種狀態: pending( 進行中)、 fulfilled( 已成功) 和rejected( 已失敗)。 只有異步操做的結果, 能夠決定當前是哪種狀態, 任何其餘操做都沒法改變這個狀態。
  2. 一旦狀態改變, 就不會再變, 任什麼時候候均可以獲得這個結果。 Promise對象的狀態改變, 只有兩種可能: 從pending變爲fulfilled和從pending變爲rejected。 只要這兩種狀況發生, 狀態就凝固了, 不會再變了, 會一直保持這個結果, 這時就稱爲 resolved( 已定型)。 若是改變已經發生了, 你再對Promise對象添加回調函數, 也會當即獲得這個結果。

Promise缺點

  1. 沒法取消promise, 一旦新建它會當即執行, 沒法中途取消.
  2. 若是不設置回調函數, promise內部拋出的錯誤, 不會反應到外部.
  3. 當處於pending 狀態時, 沒法得知目前進展到那一階段.

靜態方法

  • Promise.reslove()
    1. 將現有對象轉換爲Promise對象
    2. 若是參數是promise實例,則直接返回這個實例
    3. 若是參數是thenabled對象(有then方法的對象),則先將其轉換爲promise對象,而後當即執行這個對象的then方法
    4. 若是參數是個原始值,則返回一個promise對象,狀態爲resolved,這個原始值會傳遞給回調
    5. 沒有參數,直接返回一個resolved的Promise對象
  • Promise.reject()
    1. 同上,不一樣的是返回的promise對象的狀態爲rejected
  • Promise.all()
    1. 接收一個Promise實例的數組或具備Iterator接口的對象
    2. 若是元素不是Promise對象,則使用Promise.resolve轉成Promise對象
    3. 若是所有成功,狀態變爲resolved,返回值將組成一個數組傳給回調
    4. 只要有一個失敗,狀態就變爲rejected,返回值將直接傳遞給回調
    5. all() 的返回值也是新的Promise對象
  • Promise.race()
    1. 只要有一個Promise實例率先發生變化(不管是狀態變成resolved仍是rejected)都觸發then中的回調,返回值將傳遞給回調
    2. race()的返回值也是新的Promise對象

代碼用法和誤區

常見用法

  1. promise 的神奇之處在於讓咱們可以在回調函數裏面使用 return 和 throw
  2. 若是沒有任何返回,將默認返回 undefined
    loadAsync1()
    	.then(function(data1) {
    		return loadAsync2(data1)
    	})
    	.then(function(data2){
    	    return loadAsync3(data2)
    	})
    	.then(okFn, failFn)
    *******************	*****************
    loadAsync1()
    	.then(function(data1) {
    		loadAsync2(data1)
    	})
    	.then(function(data2){
    	    loadAsync3(data2)
    	})
    	.then(res=>console.log(res))	
    複製代碼

catch()與then(null, fn)

不等同狀況,此時catch捕獲並非ajaxLoad1錯誤 而是ajaxLoad2的錯誤。**看場景有時要結合起來使用**
 ```js
 ajaxLoad1()
	.then(res=>{ return ajaxLoad2() })
	.catch(err=> console.log(err))
	----------------------
	// 結合使用
ajaxLoad1()
	.then(res=>{ return ajaxLoad2() },     err=>console.log(err))
	.catch(err=> console.log(err))
 ```
複製代碼

穿透 Fall Through

若是then或catch接收的不是函數,那麼就會發生穿透行爲,因此在應用過程當中,應該保證then接收到的參數始終是一個函數ajax

new Promise(resolve=>resolve(8))
 .then(1)
 .catch(null)
 .then(Promise.resolve(9))
 .then(res=> console.log(res))
// 8 
複製代碼

用Promise實現一個Ajax操做

// 0 未初始化未調用open 
// 1.啓動 調用open 未調用 send
// 2. 發送 已調用send() 可是未響應 
// 3. 接收 已經接收部分響應數據 
// 4.完成 完成所有數據響應 
 const ajax = function (params) {
      if (!params.url) return
      const promise = new Promise((resolve, reject) => {
        const handler = function () {
          if (this.readyState !== 4) return
          if (this.status == 200) {
            try {
              let resonse = JSON.parse(this.responseText)
              resolve(resonse)
            } catch (error) {
              reject(error)
            }
          } else {
            reject(new Error(this.statusText))
          }
        }
        const xhr = new XMLHttpRequest()
        if (params.method.toLowerCase() == 'get') {
          xhr.open('get', url + '?' + formatParams(params.data));
          xhr.send()
        } else {
          xhr.open('post', url);
          xhr.send(JSON.stringify(params.data));
        }
        xhr.onreadystatechange = handler
        xhr.responseType = 'json'
        xhr.setRequestHeader('Accept', 'application/json');
      })
      return promise

      function formatParams(obj) {
        if (!data) return
        var arr = []
        for (let i in obj) {
          arr.push(`${encodeURIComponent(i)}=${encodeURIComponent(obj[i])}`)
        }
        return arr.join('&')
      }
    }
複製代碼

Promise常見問題

reject 和 catch 的區別

- promise.then(onFulfilled, onRejected)
   在onFulfilled中發生異常的話,在onRejected中是捕獲不到這個異常的。
- promise.then(onFulfilled).catch(onRejected)
  .then中產生的異常能在.catch中捕獲
複製代碼

若是在then中拋錯,而沒有對錯誤進行處理(即catch),那麼會一直保持reject狀態,直到catch了錯誤

```JS
    /* 例4.1 */
    function taskA() {
    console.log(x);
    console.log("Task A");
    }
    function taskB() {
    console.log("Task B");
    }
    function onRejected(error) {
    console.log("Catch Error: A or B", error);
    }
    function finalTask() {
    console.log("Final Task");
    }
    var promise = Promise.resolve();
    promise
    .then(taskA)    // 拋出錯誤,不繼續Task A」
    .then(taskB)   // .then沒有捕獲A拋出的錯,不打印 「Task B」
    .catch(onRejected)  // 捕獲了A的錯,打印錯誤信息
    .then(finalTask);   // 錯誤已經被捕獲,執行resolve
    
    -------output-------
    Catch Error: A or B,ReferenceError: x is not defined
    Final Task
 ```
複製代碼

每次調用then都會返回一個新建立的promise對象,而then內部只是返回的數據

```JS
    //方法1:對同一個promise對象同時調用 then 方法
    var p1 = new Promise(function (resolve) {
        resolve(100);
    });
    p1.then(function (value) {
        return value * 2;
    });
    p1.then(function (value) {
        return value * 2;
    });
    p1.then(function (value) {
        console.log("finally: " + value);
    });
    -------output-------
    finally: 100
------------------------------------------------------
    //方法2:對 then 進行 promise chain 方式進行調用
var p2 = new Promise(function (resolve) {
    resolve(100);
});
p2.then(function (value) {
    return value * 2;
}).then(function (value) {
    return value * 2;
}).then(function (value) {
    console.log("finally: " + value);
});
-------output-------
finally: 400
```
複製代碼

在異步回調中拋錯,不會被catch到

```JS
    // Errors thrown inside asynchronous functions will act like uncaught errors
    var promise = new Promise(function(resolve, reject) {
      setTimeout(function() {
        throw 'Uncaught Exception!';
      }, 1000);
    });
    
    promise.catch(function(e) {
      console.log(e);       //This is never called
    });
```複製代碼
相關文章
相關標籤/搜索