当前位置: 首页 > news >正文

Promise初体验

Promise是什么

JS就是操作对象上的属性和方法,对于一个对象,想要了解,我们可以直接从其身上的属性和方法入手;直接使用 console.dir(对象)打印出来

Promise对象

从上面打印出来的属性和方法,可以看到Promise是一个构造函数,有属于自己私有的all,reject,resolve,rece等方法,也有原型上面的,属于实例对象调用的方法then,catch

// Promise里面传入一个函数类型的参数,这个函数类型的参数接收两个参数resolve reject
var p=new Promise(function(resolve,reject){
     // 异步操作
     setTimeout(function(){
         console.log('icessun');  // 两秒之后打印出icessun
         resolve('icessun2'); // resolve是成功后的回调函数 里面的icessun2是传入的参数
      },2000)
  });
// 那么p是一个实例对象,可以使用then方法(Promise原型上面的方法)
p.then(function(){
    console.log(arguments);  // 会打印出一个类数组 ['icessun2']
    
 })
p.then(function(data){
    console.log(data);  // 会打印出icessun2 data接收了resolve里面的参数
 })

对于上面这段代码,首先new一个实例对象赋值给pPromise的构造函数接受一个参数,是函数;并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数;然后里面设置一个定时器setTimeout,开启一个异步操作,两秒后输出icessun,并且调用resolve方法,注意一个细节

上面的代码,只是 new了一个对象实例,并没有调用,就执行了;对于这个情况,一般是把其嵌套在一个函数里面,避免立即执行,在需要的时候去运行这个函数。

p 是一个实例对象,可以使用then方法,其里面的函数是对于resolve或者reject的调用的体现,可以接收resolve,reject传入的参数

function icessun(){
   var p=new Promise(function(resolve,reject){
        setTimeout(function(){
           console.log('icessun');
           reslove('icessun2');
        },2000);
    });
  return p; // 返回p实例,使其可以使用Promise原型上面的方法
}
icessun(); // 调用执行icessun函数 得到一个Promis对象

// 也可以直接这样调用
icessun().then(function(data){
console.log(data); // icessun2
// 一些其他的操作
// .....
});

通过上面的代码,知道then里面的函数就是经常说的回调函数callback,在icessun这个异步任务执行完成后被执行。把回调函数写法分离出来,在异步操作执行完后,用链式调用的方法执行回调函数,对于多层回调来说,非常的方便,可以继续在then的方法中继续写Promise对象并返回,继续调用then来进行回调操作,这就是Promise的作用。

链式操作

从上面看, Promise对于多层回调,可以简化其写法,使得更加的语义化;但是 Promise的精髓在于其链式操作,传递 状态,维护状态的方式使得回调函数能够及时的调用。打开 Promise的正确场景是这样:
function runAsync1(){
  var p=new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('执行完成1')
            resolve('icessun1');
         },2000);
   });

   return p; // 返回p实例对象
}
function runAsync2(){
  var p=new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('执行完成2')
            resolve('icessun2');
         },2000);
   });

   return p; // 返回p实例对象
}
function runAsync3(){
  var p=new Promise(function(resolve,reject){
        setTimeout(function(){
            console.log('执行完成3')
            resolve('icessun3');
         },2000);
   });

   return p; // 返回p实例对象
}

// 正确的打开Promise的方法
runAsync1()
           .then(function(data){
               console.log(data);
               return runAsync2();
           })
           .then(function(data){
                console.log(data);
                return runAsync3();
            })
            .then(function(data){
                console.log(data);
             })

这样能够按照顺序,每隔两秒输出每个异步回调中的内容,运行结果:

链式操作1
当然我们可以直接return数据而不是Promise对象,在后面的then方法就可以直接接收到数据,如下:

// 正确的打开Promise的方法
runAsync1()
           .then(function(data){
               console.log(data);
               return runAsync2();
           })
           .then(function(data){
                console.log(data);
                return '我是直接返回的数据';
            })
            .then(function(data){
                console.log(data);
             })

链式操作2

reject的用法

前面我们说了 resolve是执行成功的回调,那么 reject就是执行失败的回调,将 Promise的状态设置为 rejected,这样就可以在 then里面获取到,执行失败情况下的回调。
function getNumber(){
   var p=new Promise(function(resolve,reject){
      setTimeout(function(){
          var num=Math.ceil(Math.random()*10); // 生成1-10 之间的随机数 Math.ceil(): 大于或等于给定数字的最小整数
          if(num<=5){
            resolve(num);
           }else{
             reject('数字太大了')
            }
        },2000);
    });
   return p;
}

getNumber()
          .then(function(data){
               console.log('resolved');
               console.log(data);
            },function(reason,data){
                  console.log('resolved');
               console.log(reason); // 数字太大
                console.log(data); // undefined
              });

getNumber()函数执行后会出现两种情况,要么大于5,要么小于5,在then中传入了两个参数,第一个是对应resolve的回调,第二个是对应reject的回调。

catch的用法

看到这个方法,就会想到浏览器处理异常的 try...catch()方法,有错误进入 catch方法,不阻断程序的执行,其实这个方法也是来处理错误的,用来指定 reject的回调,防止程序错误,阻断后面程序的执行,使其能够继续执行。
getNumber()
           .then(function(data){
              console.log('resolve');
              console.log(data);
            })
            .catch(function(data){
               console.log('reject');
               console.log(data);
             })

其效果和上面在then里面写两个函数是一样的,这个写法的好处是当代码出现了错误的时候,不会阻断程序的执行,而是进入catach方法。

all方法的使用

Promise对象上的方法,实例不能使用,只能这个对象使用,这个方法通过了 并行执行异步操作的能力,并且在所有的异步操作完成后才执行回调
Promise
       .all([runAsync1(),runAsync2(),runAsync3()])
       .then(function(results){
          console.log(results);
        });

Promise.all来执行前面的三个异步的函数,all()接收一个数组参数,里面的执行最终都返回Promise对象,只有等三个异步操作都执行完成后才会进入到then里面,all会把所有的异步操作的结果放在一个数组中传给then,就是上面的results,代码的输出结果:

all执行结果

有了all,可以并行执行多个异步操作,并且在一个回调中处理所有的返回数据,一个常用的场景:游戏类的素材比较多的应用,打开网页的时候,预先加载需要用到的各种资源,如图片,flash以及各种静态文件,等到所有都加载完成,我们再进行页面的初始化。

race的用法

这个也是 Promise类上面的私有方法,对于前面的 all方法来说是:谁的程序执行的慢,就等谁执行完才回调。但是对于 race来说:谁的程序执行的快,就以它为标准调用回调函数,其用法基本上是一样的,把上面 runAsync1函数的延迟改为1秒
Promise
      .race([runAsync1(),runAsync2(),runAsync3()])
       .then(function(results){
         console.log(results);
        });

这三个 异步操作同样是并行执行的,但是等到1秒后,runAsync1已经执行完毕,于是then接受到了执行完毕的回调,输出回调结果;与此同时,runAsyn2runAsyn3也继续执行,输出了执行的结果,但是不能回调then方法。

race的用法

这个方法的使用场景很多,比如可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作:

// 请求某个图片资源 异步
function requestImg(){
    var p=new Promise(function(resolve,reject){
        var img=new Image(); // 创建一个图片对象实例 Image后面没有参数的时候,括号可以省略
        img.src='xxxxx'; // 给对象上面的属性设置属性值
        img.onload=function(){
           resolve(img); // 图片成功加载的时候,把img对象作为参数传到回调函数里面
         }
     });
   return p; // 当调用这个函数的时候可以使用then方法
 }

 // 延时函数 给请求计时
 function timeout(){
    var p=new Promise(function(resolve,reject){
         setTimeout(function(){
            reject('图片请求超时');
          },4000);
     });
     return p;
  } 

Promise.race([requsetImg(),timeout()])
       .then(function(results){
           console.log(results); // 图片成功加载会把图片的路径打印在控制台
        })
        .catch(function(reason){
         console.log(reason); // 失败会提示加载失败
         })

requestImg函数会异步请求一张图片,图片地址写错,肯定是无法加载图片请求。timeout函数是一个延时4秒的异步操作,把这两个返回Promise对象的函数放到race里面,如果4秒内图片请求成功,就会回调then方法,执行正常的流程,否则进入catch方法,显示图片请求超时。

请求超时的结果

正确的请求的结果

相关文章:

  • PHP 使用GD库生成二维码 实现圆角
  • session一致性架构设计
  • 《shell编程实战》第4章shell变量进阶(上)
  • 批量实现多台服务器之间ssh无密码登录的相互信任关系
  • 与Bob McWhirter的问答:WildFly Swarm更名为Thorntail项目
  • AsyncTask实现原理
  • 最简单的无缝轮播
  • c中perror函数
  • 小身材超能量Oracle新一代数据库机帮助所有规模企业迈向云端
  • Confluence 6 注册单一小工具
  • Redis分布式锁的try-with-resources实现
  • shell脚本案例(五)利用nmap批量扫描存活主机
  • Echarts关于仪表盘
  • mysql 查询当天、本周,本月,上一个月的数据---https://www.cnblogs.com/benefitworld/p/5832897.html...
  • php实现求数组中出现次数超过一半的数字(isset($arr[$val]))(取不同数看剩)(排序取中)...
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • express.js的介绍及使用
  • Git初体验
  • JS字符串转数字方法总结
  • Netty+SpringBoot+FastDFS+Html5实现聊天App(六)
  • Wamp集成环境 添加PHP的新版本
  • WebSocket使用
  • Web标准制定过程
  • 基于Android乐音识别(2)
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 通过npm或yarn自动生成vue组件
  • 我的面试准备过程--容器(更新中)
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • #图像处理
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • ( 10 )MySQL中的外键
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (MATLAB)第五章-矩阵运算
  • (附源码)springboot 房产中介系统 毕业设计 312341
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (一)为什么要选择C++
  • (译)2019年前端性能优化清单 — 下篇
  • (转)C#调用WebService 基础
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .NET Core中的去虚
  • .Net Winform开发笔记(一)
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .net开源工作流引擎ccflow表单数据返回值Pop分组模式和表格模式对比
  • .NET命名规范和开发约定
  • .net网站发布-允许更新此预编译站点
  • .net中生成excel后调整宽度
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • ::
  • @Conditional注解详解
  • [android] 看博客学习hashCode()和equals()
  • [BZOJ4016][FJOI2014]最短路径树问题