深刻理解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
    });
```复制代码
相关文章
相关标签/搜索