博客
关于我
关于js中对于Promise的深入理解
阅读量:358 次
发布时间:2019-03-05

本文共 13324 字,大约阅读时间需要 44 分钟。

一、promise 的认识

  1. js的单线程

    1)javascript的执行环境是单线程的
    2)单线程:指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务,这个任务可称为主线程,但是实际上还有其他线程,如事件触发线程、ajax请求线程等

  2. 同步与异步

    1)同步模式:也就是单线程模式,一次只能执行一个任务,函数调用后需等到函数执行结束,返回执行的结果,才能进行下一个任务,如果这个任务执行的时间较长,就会导致线程阻塞
    2)异步模式:可以一起执行多个任务,函数调用后不会立即返回执行的结果,如果任务A需要等待,可先执行任务B,等到任务A结果返回后再继续回调

  3. 回调函数

    1)回调函数:一段可执行的代码段,它以参数的形式传递给其他代码,在其合适的时间执行这段回调函数的代码,可以理解为执行完回来调用的函数
    2)回调函数可以运用在同步调用,回调函数一般是最后执行的
    实例代码:

// 同步回调,回调函数一般是最后执行的   //  before    3S后出现  callback  after   // 将f2函数作为参数传入f1中,先执行输出before,判断f2是否是回调函数,再判断是否决定执行   // f2是回调函数,3s后执行,输出callback,然后输出after   var f1 = function(callback){          console.log("before");       (callback && typeof(callback) === "function") && callback();       console.log("after");   };   var f2 = function(callback){          var start = new  Date();       while((new Date()-start)<3000){   }       console.log("callback");   };   f1(f2);

3)回调函数可以运行在异步调用,回调函数可能一段时间后执行或不执行,未达到执行的条件

实例代码:

// 异步调用,可能一段时间后执行或不执行    // 常见的异步回调有setTimeout()、setInterval(),还有ajax请求    function request(url,parm,successFun,errorFun){           $.ajax({               type:'GET',            url:url,            parm:parm,            async:true,            success:successFun,            error:errorFun        });    }    request("test03.html","",function(data){           // 请求成功,对请求回来的数据进行处理       console.log("请求成功后回调",data);    },function(error){           // 请求失败,返回请求失败的信息        console.log("请求失败了",error);    });

4.promise的写法

1)Promise对象代表一个未完成、但预计将来会完成的操作 ,是一种异步的解决方案
它的三种状态为:
pending:初始值,不是fulfilled,也不是rejected
fulfilled:代表操作成功,解决
rejected:代表操作失败,拒绝
2)Promise有两种状态改变的方式,既可以从pending转变为fulfilled,也可以从pending转变为rejected。一旦状态改变,就「凝固」了,会一直保持这个状态,不会再发生变化。当状态发生变化,promise.then绑定的函数就会被调用
注意:Promise一旦新建就会立即执行,无法取消
3)实例如下:

// promise是一个回调函数    // resolve  异步操作执行成功后的回调函数,将Promise的状态置为fullfiled    // reject  异步操作执行失败后的回调函数,将Promise的状态置为rejected    var p = new Promise(function(resolve,reject){           //  2s后输出     执行完成        setTimeout(function(){               console.log("执行完成");            resolve("操作成功");            reject("操作失败");        },3000);    });

4)优化,实际上Promise上的实例_promise是一个对象,不是一个函数,在声明的时候Promise传递的参数函数会立即执行。所以promise一般是包在一个函数中,在它的外层裹上一层函数,在需要的时候去运行这个函数

实例如下:

// 创建了promise对象,在runAsync()函数中return返回promise对象    //   2s后输出  执行完成    function runAsync(){           var p2 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("执行成功");                resolve("操作成功");                reject("操作失败");            },3000);        });        return p2;    }    runAsync();

二、promise的用法

  1. then的用法
    1)语法:Promise.prototype.then(onFulfilled, onRejected)
    2)对promise添加onFulfilled和onRejected回调,并返回的是一个新的Promise实例(不是原来那个Promise实例),且返回值将作为参数传入这个新Promise的resolve函数
    3)实例如下:
function runAsync(){           var p2 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("执行成功");                resolve("操作成功");                reject("操作失败");            },3000);        });        return p2;    }    runAsync();    // Promise对象上有then、catch方法,在runAsync()的返回上直接调用then方法    // then接收一个参数,是函数,并且会拿到我们在runAsync中调用resolve时传的的参数    //  3s后输出   执行成功   操作成功    runAsync().then(function(data){          console.log(data);    });

4)callback的实现

// 封装回调函数    // 2s后输出  执行成功  操作成功    // 假如callback是一个异步操作,执行完成后有相应的回调函数,如果层层嵌套回调,会形成回调地狱    // promise可以在then方法中继续写promise对象并且返回,继续调用then来进行回调操作    function runAsync2(callback){           setTimeout(function(){               console.log("执行成功");            callback("操作成功");        },3000);    }    runAsync2(function(data){          console.log(data);    });

5)回调地狱

代码层层嵌套,环环相扣,很明显,逻辑稍微复杂一些,这样的程序就会变得难以维护,通过Promise构造函数才可以进行较好的解决
回调地狱的影响
代码臃肿
可读性差
耦合度过高,可维护性差
代码复用性差
容易滋生 bug
只能在回调里处理异常

  1. 链式操作的用法
    1)promise,用维护状态、传递状态的方式来使得回调函数能够及时调用,它比传递callback函数要简单、灵活的多
    2)实例如下:
// runAsync1() 函数    function runAsync1(){           var p1 = new Promise(function(resolve,reject){              setTimeout(function(){                  console.log("异步任务1执行完成");               resolve("操作成功1");               reject("操作失败");           },3000);        });        return p1;    }    // runAsync2() 函数    function runAsync2(){           var p2 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("异步任务2执行完成");                resolve("操作成功2");                reject("操作失败");            },3000);        });        return p2;    }    // runAsync3() 函数    function runAsync3(){           var p3 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("异步任务3执行完成");                resolve("操作成功3");                reject("操作失败");            },3000);        });        return p3;    }  /*    *  输出   异步任务1执行完成   操作成功1    *         异步任务2执行完成   操作成功2    *         异步任务3执行完成   操作成功3    */    //  每隔三秒就输出每个异步回调中的内容,通过promise的then方法,继续写promise对象并且返回    //  继续调用then来进行回调操作,形成链式调用,不会形成回调地狱    runAsync1().then(function(data){           console.log(data);        return runAsync2();    }).then(function(data){           console.log(data);        return runAsync3();    }).then(function(data){           console.log(data);    });

3)直接return数据而不是promise对象,在后面的then中就可以接收到数据了

实例如下:

// runAsync1() 函数   function runAsync1(){          var p1 = new Promise(function(resolve,reject){             setTimeout(function(){                 console.log("异步任务1执行完成");              resolve("操作成功1");              reject("操作失败");          },2000);       });       return p1;   }   // runAsync2() 函数   function runAsync2(){          var p2 = new Promise(function(resolve,reject){              setTimeout(function(){                  console.log("异步任务2执行完成");               resolve("操作成功2");               reject("操作失败");           },3000);       });       return p2;   }   // runAsync3() 函数   function runAsync3(){          var p3 = new Promise(function(resolve,reject){              setTimeout(function(){                  console.log("异步任务3执行完成");               resolve("操作成功3");               reject("操作失败");           },3000);       });       return p3;   } /*    *  输出   异步任务1执行完成   操作成功1    *         异步任务2执行完成   操作成功2    *         返回数据    */   // 直接return数据而不是promise对象,在后面的then中就可以接收到数据了   runAsync1().then(function(data){          console.log(data);       return runAsync1();   }).then(function(data){          console.log(data);       return "返回数据";   }).then(function(data){         console.log(data);   });
  1. rejecte的用法
    1)语法:Promise.reject(reason)
    2)rejecte会让Promise对象立即进入rejected状态,并将错误对象传递给then指定的onRejected回调函数
    3)reject会把Promise的状态置为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调
    4)实例如下:
function getNumber(){          var p1 = new Promise(function(resolve,reject){             setTimeout(function(){                //  生成1-10的随机数              var num = Math.ceil(Math.random()*10);              //  成功后的回调              if(num<5){                     resolve(num);              }else{                 // 失败后的回调                  reject("数字不符合");              }          },3000);       });        return p1;    }    /*    *  resolve时输出   操作成功  3    *  reject时输出    操作失败  数字不符合    */    // getNumber函数用来异步获取一个数字,3秒后执行完成    // 当数字小于5的时候,异步操作执行成功后的回调函数,将Promise的状态置为fullfiled    // 当数字不小于5的时候,异步操作执行失败后的回调函数,将Promise的状态置为rejected    // 运行getNumber并且在then中传了两个参数,then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调    getNumber().then(            function(data){                   console.log("操作成功");                console.log(data);            },            function(reject,data){                   console.log("操作失败");                console.log(reject);            }    );
  1. catch的用法
    1)语法:Promise.prototype.catch(onRejected)
    2)该方法是.then(undefined, onRejected)的别名,用于指定发生错误时的回调函数
    3)catch它和then的第二个参数一样,用来指定reject的回调
    实例如下:
function getNumber(){          var p1 = new Promise(function(resolve,reject){             setTimeout(function(){                //  生成1-10的随机数              var num = Math.ceil(Math.random()*10);              //  成功后的回调              if(num<5){                     resolve(num);              }else{                 // 失败后的回调                  reject("数字不符合");              }          },3000);       });        return p1;    }    /*     *  resolve时输出   操作成功  3     *  reject时输出    操作失败  数字不符合     */    getNumber().then(function(data){           console.log("操作成功");        console.log(data);    }).catch(function(data){          console.log("操作失败");        console.log(data);    });

4)catch在执行resolve的回调时,也就是then的第一个参数,如果代码出错抛出异常,那么就会被catch捕获执行,catch的这个用法类似于 try/catch 的用法

实例如下:

function getNumber(){          var p1 = new Promise(function(resolve,reject){             setTimeout(function(){                //  生成1-10的随机数              var num = Math.ceil(Math.random()*10);              //  成功后的回调              if(num<5){                     resolve(num);              }else{                 // 失败后的回调                  reject("数字不符合");              }          },3000);       });        return p1;    } /*    *  resolve时输出   操作成功  1  操作失败   ReferenceError: data2 is not defined    *   reject时输出    操作失败  数字不符合    */    //  代码出错抛出异常,进入到catch方法,把错误原因传到了data参数中    getNumber().then(function(data){           console.log("操作成功");        console.log(data);        // 未声明定义的变量 data2        console.log(data2);    }).catch(function(data){          console.log("操作失败");       console.log(data);    });
  1. all的用法
    1)语法:Promise.all(iterable)
    2)该方法用于将多个Promise实例,包装成一个新的Promise实例,Promise.all方法接受一个数组(或具有Iterator接口)作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve转换为一个promise)。它的状态由这三个promise实例决定
    3)当p1, p2, p3状态都变为fulfilled,p的状态才会变为fulfilled,并将三个promise返回的结果,按参数的顺序(而不是 resolved的顺序)存入数组,传给p的回调函数。当p1, p2, p3其中之一状态变为rejected,p的状态也会变为rejected,并把第一个被reject的promise的返回值,传给p的回调函数
    4)all方法可以并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。也可以理解为可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据。all是谁最慢,以谁为准执行回调
    5)实例如下:
function runAsync1(){           var p1 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("异步任务1执行完成");                resolve("操作成功1");                reject("操作失败");            },1000);        });        return p1;    }    // runAsync2() 函数    function runAsync2(){           var p2 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("异步任务2执行完成");                resolve("操作成功2");                reject("操作失败");            },3000);        });        return p2;    }    // runAsync3() 函数    function runAsync3(){           var p3 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("异步任务3执行完成");                resolve("操作成功3");                reject("操作失败");            },3000);        });        return p3;    }  // all  谁最慢,以谁为准执行回调    /*    * 输出     异步任务1执行完成  异步任务2执行完成   异步任务3执行完成    *         (3) ["操作成功1", "操作成功2", "操作成功3"]    */    // promise.all接收一个数组参数,三个异步操作并行执行    // 在它们都执行完以后进入到then里面,all会把所有异步操作的返回结果数据放进一个数组中传给then    Promise.all([runAsync1(),runAsync2(),runAsync3()]).then(function(result){            console.log(result);    });
  1. race的用法
    1)语法:Promise.race(iterable)
    2)该方法同样是将多个Promise实例,包装成一个新的Promise实例
    3)Promise.race方法同样接受一个数组(或具有Iterator接口)作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilled或rejected),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数
    4)并行执行异步操作的能力,与all类似,不同的是谁最快,以谁为准执行回调
    5)实例如下:
function runAsync1(){           var p1 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("异步任务1执行完成");                resolve("操作成功1");                reject("操作失败");            },1000);        });        return p1;    }    // runAsync2() 函数    function runAsync2(){           var p2 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("异步任务2执行完成");                resolve("操作成功2");                reject("操作失败");            },3000);        });        return p2;    }    // runAsync3() 函数    function runAsync3(){           var p3 = new Promise(function(resolve,reject){               setTimeout(function(){                   console.log("异步任务3执行完成");                resolve("操作成功3");                reject("操作失败");            },3000);        });        return p3;    }   /*    * 输出    异步任务1执行完成  操作成功1  异步任务2执行完成  异步任务3执行完成    */    Promise.race([runAsync1(),runAsync2(),runAsync3()]).then(function(result){           console.log(result);    });

6) race的应用场景,给某个异步请求设置超时时间,并且在超时后执行相应的操作

实例如下:

// 请求某个图片资源   function requestImg(){          var p4 = new Promise(function(resolve,reject){              var img = new Image();           img.onload = function(){                  resolve(img);           };           img.src = "xxxxxx";       });       return p4;   }   //  延时函数,用于给请求计时   function timeout(){          var p5 = new Promise(function(resolve,reject){              setTimeout(function(){                 reject("请求超时,响应失败");           },6000);       });       return p5;   }   /*   * 输出    Failed to load resource: the server responded with a status of 404 (Not Found)   *         请求超时,响应失败   */   //将 requestImg()和timeout()函数并且执行异步操作,timeout()函数是一个延时6s的异步操作   // 将它们返回Promise对象的函数放进race,就会进行比赛,看谁会先   // 如果6s内图片资源请求成功,那么就进入到then方法中,如果6s内图片资源请求失败,被catch捕获报错   Promise.race([requestImg(),timeout()]).then(function(result1){          console.log(result1);   }).catch(function(result2){          console.log(result2);   });

转载地址:http://fapg.baihongyu.com/

你可能感兴趣的文章
关于js中对于Promise的深入理解
查看>>
对于js中的this指向的深入理解
查看>>
杭电 2007 平方和与立方和(输入数据的大小顺序并不能默认)
查看>>
十大排序算法之三:插入排序(Python)
查看>>
利用Python实现循环队列
查看>>
十大排序算法之四:希尔排序(Python)
查看>>
利用递归实现二叉树的前中后序遍历(Python)
查看>>
A*寻路算法(Python)
查看>>
Python刷题输入输出
查看>>
冒泡排序又来啦(C/C++版本)
查看>>
python负数存储
查看>>
求二维数组中最大值的位置
查看>>
python中sort和sorted的区别
查看>>
防碰撞算法
查看>>
在vue中添加echarts
查看>>
vue中echart数据动态切换,一看就懂
查看>>
Python实现理解树,树的遍历,二分查找
查看>>
Python3.6爬虫记录
查看>>
搞清楚Spring Cloud架构原理的这4个点,轻松应对面试
查看>>
1月份2月份GitHub上最热门的23个Java开源项目
查看>>