Promise

参考文献:《JavaScript重难点实例精讲》周雄

1.诞生背景

Promise诞生以前,在处理一个异步请求时,我们通常是在回调函数中做处理.

 $.ajax({
            url:'url1',
            success:function(){
                //回调函数
        }
     });

假如在一个行为中,需要执行多个异步请求,每一个请求又需要依赖上一个请求的结果,按照回调函数的处理方法,代码如下所示。

 //第一个请求
        $.ajax({
            url:'url1',
            success:function(){
                //第二个请求
                $.ajax({
                    url:'url2',
                    success:function(){
                        //第三个请求
                        $.ajax({
                            url:'url3',
                            success:function(){
                                //成功回调
                            }
                        })
                    }
                })
            }
        })

一个行为所产生的异步请求可能比这个还要多,这就会导致代码的嵌套太深,引发“回调地狱”。
“回调地狱”存在以下几个问题:
(1)代码臃肿,可读性差。
(2)代码耦合度高,可维护性差,难以复用。
(3)回调函数都是匿名函数,不方便调试。

为了解决回调地狱,Promise应运而生。

2.Promise的生命周期

每一个Promise对象都有3种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。
创建成功时处于pending状态,状态的改变只有两种可能。pending转fulfilled或者pending转reject。
状态一旦改变,就不能再改变。

3 Promise的基本用法

(1)Promise对象本身是一个构造函数,可以通过new操作符生成Promise的实例。

 const promise = new Promise((resolve,reject)=>{
            //异步请求处理
            if(/异步请求标识/){
                //判断结果为true,异步请求执行成功,调用resolve()函数。
                //resolve一旦执行,promise的状态就从pending变为fulfilled
                resolve();
            }else{
                //判断结果为false,异步请求执行失败,调用reject()函数
                //reject一旦执行,promise的状态就从pending变为rejected
                reject();
            }
        });

resolve()函数和reject()函数可以传递参数,作为后续.then()函数或者.catch()函数执行时的数据源。

(2)注意:Promise在创建后会立即调用,然后等待执行resolve()函数或者reject()函数来确定Promise的最终状态。

let promise = new Promise(function(resolve,reject){
            console.log('Promise');
            resolve();
        });
        promise.then(function(){
            console.log('resolved');
        });
        console.log('Hello');
        //先后输出'Promise','Hello','resolved'
        //输出Promise,执行resolve()函数,触发then()函数指定回调函数的执行,但它需要等当前线程中的所有同步代码执行完毕,因此会先执行最后一行同步代码,输出“Hello”

(3)当一个Promise实例创建好后,使用then()函数和catch()函数进行成功和失败的异步处理。

(3.1)then()函数,表示在Promise实例状态改变时执行的回调函数。
解决上面“回调地狱”:

 const promise = new Promise((resolve,reject)=>{
            resolve(1);
        });
        //then()函数链式调用
        promise.then((result)=>{
            console.log(result);//1
            return 2;
        }).then((result)=>{
            console.log(result);//2
            return 3;
        }).then((result)=>{
            console.log(result);//3
        })

注意:在then()函数中不能返回Promise实例本身,否则会出现Promise循环引用的问题,抛出异常。

const promise = Promise.resolve()
        .then(()=>{
            return promise;  //TypeError:Chaining cycle detected for promise #<Promise>
        });

虽然then()函数能够处理rejected状态的Promise的回调函数,但是并不推荐这么做,推荐catch()函数处理。

(3.2)catch()函数,与then()函数是成对存在的,then()函数是Promise执行成功之后的回调,而catch()函数是Promise执行失败之后的回调,它所接收的参数就是执行reject()函数时传递的参数。

使用try...catch
 const promise = new Promise((resolve,reject)=>{
            try{
                throw new Error('test');
            }catch(err){
                reject(err);
            }
        });
        promise.catch((err)=>{
            console.log(err);//Error:test
        });

实际只要在Promise执行过程中出现异常,就会自动抛出,并触发reject(err),以上等同于以下功能。
const promise = new Promise((resolve,reject)=>{
            throw new Error('test');
        });
        promise.catch((err)=>{
            console.log(err);//Error:test
        });

空指针测试异常:
在Promise接收的函数体中引用null的name属性时,会抛出一个异常。

const promise = new Promise((resolve,reject)=>{
            null.name;
        });
        promise.catch((err)=>{
            console.log(err);//TypeError:Cannot read property 'name' of null
        });

如果一个Promise的状态已经变成fulfilled成功状态,再去抛出异常,是无法触发catch()函数的。状态一旦改变,永久保持。

const promise = new Promise((resolve,reject)=>{
          resolve(1);
          throw new Error('test');
        });
        Promise
        .then((result)=>{
            console.log(result);//1
        })
        .catch((err)=>{
            console.log(err);
        })

(4)Promise静态函数
(4.1)Promise.all()函数,将多个Promise实例包装成一个新的Promise实例。

const p = Promise.all([p1,p2,p3]);

返回的新Promise实例p的状态由3个Promise实例p1、p2、p3共同决定,会有2种情况:
*1.只有p1、p2、p3全部的状态都变为fulfilled成功状态,p的状态才会变为fulfilled状态,此时p1、p2、p3的返回值组成一个数组,作为p的then()函数的回调函数的参数。
*2.只要p1、p2、p3中有任意一个状态变为rejected失败状态,p的状态就变为rejected状态,此时第一个被reject的实例的返回值会作为p的catch()函数的回调函数的参数。

注意:作为参数的Promise实例p1、p2、p3,如果已经定义了catch()函数,那么当其中一个Promise状态变为rejected时,并不会触发Promise.all()函数的catch()函数。

const p1 = new Promise((resolve,reject)=>{
          resolve('success');
      })
      .then(result=>result)
      .catch(e=>e);

      const p2 = new Promise((resolve,reject)=>{
          throw new Error('error');
      })
      .then(result=>result)
      .catch(e=>e);

      Promise.all([p1,p2])
      .then(result=>console.log(result))//['success',Error:error]
      .catch(e=>console.log(e));

如果想要Promise.all()函数能触发catch()函数,那么就不要在p1、p2实例中定义catch()函数。

const p1 = new Promise((resolve,reject)=>{
          resolve('success');
      })
      .then(result=>result);

      const p2 = new Promise((resolve,reject)=>{
          throw new Error('error');
      })
      .then(result=>result);

      Promise.all([p1,p2])
      .then(result=>console.log(result))
      .catch(e=>console.log(e));//抛出异常,Error:error

(4.2)Promise.race()函数
Promise.all()函数作用于多个Promise实例上,返回一个新的Promise实例,表示的是如果多个Promise实例中有任何一个实例的状态发生改变,那么这个新实例的状态就随之改变,而最先改变的那个Promise实例的返回值将作为新实例的回调函数的参数。

const p = Promise.race([p1,p2,p3]);

当p1、p2、p3这3个Promise实例中有任何一个执行成功或者失败时,由Promise.race()函数生成的实例p的状态就与之保持一致,并且最先那个执行完的实例的返回值将会成为p的回调函数的参数。

(4.3)Promise.resolve()函数
它等价于在Promise函数体内调用resolve()函数。
*1.Promise.resolve()函数执行后,Promise的状态会立即变为fulfilled,然后进入then()函数中做处理。

Promise.resolve('hello');
      //等价于
new Promise(resolve=>resolve('hello'));

*2.在Promise.resolve(param)函数中传递的参数param,会作为后续then()函数的回调函数接收的参数。

Promise.resolve('success').then(result=>console.log(result));//success

(4.4)Promise.reject()函数
等价于在Promise函数体内调用reject()函数。

 const p = Promise.reject('出错了');
 //等价于
 const p = new Promise((resolve,reject)=>reject('出错了'));

在Promise. reject (param)函数中传递的参数param,会作为后续catch()函数的回调函数接收的参数。

Promise.reject('fail').catch(result=>console.log(result));//fail
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值