Promise 请求基础操作和简单封装

Promise 是什嘛

  • ES6 语法规范中新加的内置类,用来处理 js 中异步编程的,而我们所谓的 Promise 设计模式,就是基于 promise 对异步操作进行管理 ;主要解决回调地狱
  • promose 是一个内置类,所以创建一个 promise:new Promise([executor]): 第一个执行函数必须传递,这里的 executor 是一个回调函数下面简称 exe
  1. new promise 的时候就会把 exe 执行,创建 promise 的一个实例(exe 是 promise 类的一个回调函数,promise 内部会把它执行)
  2. promise 不仅把 exe 执行,而且还给 exe 传递两个参数(两个参数也是函数类型)
    resolve 函数:它执行代表 promise 处理的异步事情是成功的,把 promise 的状态改为 fulfilled
    reject 函数:它执行代表 promise 处理的异步事情是失败的,把 promise 的状态改为 rejected
  3. exe 函数中放的就是当前要处理的异步操作事情
    let promiseExamp = new Promise((resolve, reject) => {这里一般存放的都是我们即将要处理的异步任务,任务成功我们执行 resolve,任务失败我们执行 reject(当然写同步的也可以)}

异步编程中的回调地狱

  • 一个回调函数嵌一个回调函数再嵌一个回调函数再嵌一个回调函数再嵌一个回调函数再嵌一个回调函数再嵌一个回调函数再嵌一个回调函数再嵌一个回调函数再嵌一个回调函数… 就是回调地狱。
  • 一个小例子:
    从服务器获取某个学生的基本信息 (score-id) -> 基于分数的 ID 获取到当前学生各项成绩 -> 基于某一项成绩获取他在学校的排名

promise 三个状态: pending 进行中 fulfilled 成功 rejected 失败

  • 改变状态有两种可能 pending–>fulfilled pending–> rejected ;
    下面展示一些 内联代码片
 let p = new Promise(function (resolve, reject) {
           // resolve();  // 调用resolve代表执then中的第一个回调,resolve代表的是成功态
            reject(); // // 调用reject ,就代表执行then的的第二个回调;失败态
        }).then(function () {
            console.log(1);
        }, function () {
            console.log(2);
        }).then(function () {

        }, function () {

        })
promise 写法示例
// An highlighted block
let p = new Promise(function(resolve,reject){
            setTimeout(function(){
                console.log("买菜");
                resolve();
            },3000)
        }).then(function(){
            return new Promise(function(resolve,reject){
                setTimeout(function(){
                    console.log("洗菜");
                    resolve()
                },2000)
            })
        }).then(function(){
            return new Promise(function(resolve,reject){
                setTimeout(function(){
                    console.log("做菜");
                    resolve()
                },1000)
            })
        })
        //打印结果是 买菜,洗菜,做菜;

Promise.prototype.then()

  • then : 在Promise的原型上的一个方法; p.then 也会默认返回一个promise实例,而且默认是成功的;如果在then的回调函数中也返回一个promise实例,那么这个promise实例就会覆盖默认返回的实例影响下一个then中的回调函数;
  • 如果return promise的实例那么下面的then就会受实例的影响,在实例执行完后再执行then 如果没有return promise的实例那么下面的then就不受影响,直接执行
  • 示例1
// An highlighted block
<script>
    let p = new Promise(function (resolve, reject) {
        setTimeout(function () {
            if (Math.random() > 0.5) {
                resolve(100);
            } else {
                reject();
            }
        }, 1000)
    })
    p.then(function (a) {
        console.log(a);//上一个返回resolve时执行
        return new Promise(function (resolve, reject) {
            resolve();
        });
    }, function () {
        console.log("不买");//是一个返回reject时执行
    }).then(function () {
        // 第二个then的方法受第一个then返回值影响;
        console.log("成功")
    }, function () {
        console.log("失败")
    })
</script>
  • 示例2
  let p = new Promise(function(resolve,reject){
            resolve()
        });
        p.then(function(){
            // 如果这里面return一个promise的实例,下一个then中的回调受这个实例的影响;
            return new Promise(function(resolve,reject){
                setTimeout(function(){
                    console.log(1);
                    resolve();
                },2000)
            })
            // setTimeout(function(){
            //     console.log(3);
            // },2000)
        },function(){

        }).then(function(){
            console.log(2);
        })
       // return promise 实例时 打印出来时 1,2
      //  定时器 时 打印出来是 2,3 因为 .then里面的console是同步的 ,定时器是异步的

Promise.prototype.catch()

  • 一般来说,不要在then中定义第二个reject函数;一般使用catch;理由是第二种写法可以捕获前面then方法执行中的错误,也更接近同步的写法(try/catch)。
  • 如果在then中抛出错误,就会执行下面的catch 如果then中有一个异常,也会抛出错误只要then链中有一个异常,就会执行最后的catch;只要在then中有失败的回调,就不再执行最后的catch了只要其中一个then的回调失败,就不再执行下面的then中的回调,而是直接走catch
let p = new Promise(function (resolve,reject) {
          resolve();
      })
      p.then(function () {
          console.log(1);
      }).then(function () {
             console.log(3);
      }).then(function () {
             console.log(a);
      }).catch(function () {
          console.log(2);
      })

      //显示 1 3 2

Promise.prototype.finally()

  • promise 的finally 是不管成功还是失败,都会执行的回调
  • 这是会等到promise实例状态改变以后会触发的回调,是一个异步的;
let p = new Promise(function(resolve,reject){
  resolve();
})
p.then(function(){
  console.log(1); 
  console.log(a);
}).catch(function(){
  console.log(55);
}).finally(function(){
  // 这是会等到promise实例状态改变以后会触发的回调,是一个异步的;
  console.log(1000);
})
console.log(999);
//999  55  1000

Promise.all()

  1. Promise.all : 用于多个实例,返回一个新promise实例 全部成功状态才是成功,只要有一个失败状态就是失败
  2. 如果不是Promise 实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。
let p1 = new Promise(function(resolve,reject){
            setTimeout(function(){
                reject(100);
            },3000)
        }) 
        let p2= new Promise(function(resolve,reject){
            setTimeout(function(){
                reject(200);
            },2000)
        }) 
        let p3= new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(300);
            },4000)
        });
        let p = Promise.all([p1,p2,p3]) //全部执行完才会返回结果
        p.then(function(data){
            // 会将所有成功的数据组装一个新数组,传递给这个回调函数
            console.log(data);
            
        }).catch(function(data){
            // 只要遇到一个失败,就将失败的这个值传递给这个回调
            console.log(data);
        })

Promise.race()

  • Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
  • Promise.race()方法的参数与Promise.all()方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。
 let p1 = new Promise(function(resolve,reject){
            setTimeout(function(){
                reject(100);
            },13000)
        }) 
        let p2= new Promise(function(resolve,reject){
            setTimeout(function(){
                reject(200);
            },12000)
        }) 
        let p3= new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve(300);
            },4000)
        });
        let p = Promise.race([p1,p2,p3])
        
        p.then(function(){
            console.log("成功");
            
        }).catch(function(){
            console.log("失败");
            
        })
  打印结果 是  成功 因为p3先执行完
//谁先执行返回的结果是啥p的结果就是啥
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。

Promise.resolve()

  • Promise.resolve: 将一个对象转成一个promise的实例;返回值可以调用then方法
 Promise.resolve("foo").then(function(){

        })
        new Promise(function(resolve,reject){
            resolve("foo")
        });

        let p  = Promise.resolve();
        p.then(function(){

        })

ajax的串行与解决

  • 只有第一个请求成功才能执行第二个,第二个成功才能执行第三个,最后一个请求成功后拿到了每一次请求的所有数据。 例如:
$.ajax({
  url:'/baseInfo',
  method:'GET',
  data:{
    name:'zhanglu'
  },
  success:result => {
    let scoreId = result.scoreId;

    $.ajax({
      url:'/scoreInfo',
      method:'GET',
      data:{
        id:scoreId
      },
      success:result => {
        let chinese = result.chinese;

        $.ajax({
          url:'/paiming',
          method:'GET',
          data:{
            num:chinese
          },
          success:result => {

          }
        });
      }
    });
  }
});
  • promise解决串行的办法
 let p = new Promise(function(resolve,reject){
            resolve()
        });
        p.then(function(){
            // 如果这里面return一个promise的实例,下一个then中的回调受这个实例的影响;
            return new Promise(function(resolve,reject){
              $.ajax({
				  url:'/baseInfo',
				  method:'GET',
				  data:{
				    name:'zhanglu'
				  },
				  success:result => {
				    let scoreId = result.scoreId;
				    resolve(scoreId )
				}
				})
            })
        }).then(function(value){
              return new Promise(function(resolve,reject){
	              $.ajax({
					  url:'/scoreInfo',
					  method:'GET',
					  data:{
					    name:'zhanglu'
					  },
					  success:result => {
					    let scoreId = result.scoreId;
					    resolve(scoreId )
					}
					})
            })
        }).then(res=>{
                 ......
         })

ajax的并行与解决

		let chi = 100,
		    eng = 12,
		    math = 98;
		let chiPai,
		    engPai,
		    mathPai;
		let count = 0;
		function func () {
		  if(count >= 3) {
		    // 处理自己要做的事情
		  }
		}
		
		$.ajax({
		  url:'/pai ? chi = ' + chi,
		  success:result => {
		    chiPai = result;
		    count++;
		    func();
		  }
		});
		$.ajax({
		  url:'/pai ? eng = ' + eng,
		  success:result => {
		    engPai = result;
		    count++;
		    func();
		  }
		});
		$.ajax({
		  url:'/pai ? math = ' + math,
		  success:result => {
		    mathPai = result;
		    count++;
		    func();
		  }
		});
  • promise解决并发的办法
			function ajax1 () {
			    return new Promise (resolve => {
			        $.ajax({
			            url: '/api1',
			            success: resolve
			        });
			    });
			}
			
			function ajax2 () {
			    return new Promise (resolve => {
			        $.ajax({
			            url: '/api2',
			            success: resolve
			        });
			    });
			}
			
			function ajax3 () {
			    return new Promise (resolve => {
			        $.ajax({
			            url: '/api3',
			            success: resolve
			        });
			    });
			}
			let p = Promise.all([ajax1 ,ajax2,ajax3]) //全部执行完才会返回结果
        p.then(function(data){
            // 会将所有成功的数据组装一个新数组,传递给这个回调函数
            console.log(data);
            
        }).catch(function(data){
            // 只要遇到一个失败,就将失败的这个值传递给这个回调
            console.log(data);
        })

自己简单封装一个promise

  • 首先先分析一波
let p = new MyPromise(function (resolve,reject) { //p1
        // resolve形参可以执行;所以该实参一定是个函数
        // resolve,reject : 改变当前实例的状态
           resolve()
    });
  p.then(function () {  //p 是promise的实例 .then可以执行说明then是原型链上的方法
        return new Promise(function (resolve,reject) {   // p2
            resolve();  //  执行p2事件池中的方法;p2事件池中有个p1 的resolve,p1的resolve执行;会把p1成功事件池中的方法执行;
        })
    })
     // 第一个resolve  要执行p这个实例中成功事件池中的方法;这是一个异步的操作;暂时异步事件池中的方法是不执行;

    // 第二个resolve :  执行p2事件池中的方法;p2事件池中有个p1 的resolve,p1的resolve执行;会把p1成功事件池中的方法执行;

    // 第一个then : 把then中的方法放入到p的成功事件池中;并且返回一个p1的promise实例;

    // 第二个then :p1.调用的then;把then中放到了p1.的成功事件池中;
  • 封装的代码
<script>
    class MyPromise{
        constructor(excutor){
            this.state = "pending";// 当前实例有个state,默认值是pending;
            // 当初始化promise实例时,新增两个事件池;一个成功一个失败;
            this.fulfilledEvent = [];
            this.rejectedEvent=[];
            // resolve : 1. 改变状态;2.让成功事件池中的方法都执行;
            let resolve=(result)=>{
                // 如果不是pending状态,那么promise状态已经发生了改变,不需要再执行;
                if(this.state!=="pending")return;
                this.state="fulfilled";
                clearTimeout(this.timer);
                this.timer = setTimeout(()=>{
                    // 事件池中的方法执行是一个异步的;
                    this.fulfilledEvent.forEach(item=>{
                        if(typeof item==="function"){
                            item(result)
                        }
                    })
                },0)
            };
            let reject = (result)=>{
                if(this.state!=="pending")return;
                this.state="rejected";
                clearTimeout(this.timer);
                this.timer = setTimeout(()=>{
                    this.rejectedEvent.forEach(item=>{
                        if(typeof item==="function"){
                            item(result)
                        }
                    })
                },0)
            };
           try{
               excutor(resolve,reject)
           }catch(e){
               reject(e);
           }
        }
        // 订阅方法;
        then(resolveFn,rejectFn){
            //如果then不传参数;给函数赋默认的匿名函数;
            if(resolveFn===undefined){
                resolveFn=()=>{};
            }
            if(rejectFn===undefined){
                rejectFn=()=>{
                    throw new Error();
                }
            }
            return new MyPromise((resolve,reject)=>{// p1  p1中的resolve--> this指向p1;
                // 必须验证resolveFn是否是一个promise的实例
                this.fulfilledEvent.push((result)=>{
                    try{
                        let x = resolveFn(result);
                        // x===p2 resolve 存储到了p2的事件池中;
                        x instanceof MyPromise?x.then(resolve,reject):resolve();
                    }catch(e){
                        reject(e);
                    }
                });
                this.rejectedEvent.push((result)=>{
                  try{
                      let x = rejectFn(result);
                      // x===p2 resolve 存储到了p2的事件池中;
                      x instanceof MyPromise?x.then(resolve,reject):resolve();
                  }catch(e){
                      reject(e)
                  }
                });
            })
        }
    }

    let  p  = new MyPromise(function (resolve,reject) {
       setTimeout(function () {
          resolve(1)
       },2000)
    })
    p.then(function (val) {

        /*return new MyPromise(function (resolve,reject) {
            setTimeout(function () {
                resolve(2);
            },2000)
        })*/
    },function () {
        
    }).then(
        function () {
            
        }
    )  
</script>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值