资讯专栏INFORMATION COLUMN

Promise初体验

leap_frog / 3091人阅读

摘要:把回调函数写法分离出来,在异步操作执行完后,用链式调用的方法执行回调函数,对于多层回调来说,非常的方便,可以继续在的方法中继续写对象并返回,继续调用来进行回调操作,这就是的作用。

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

从上面打印出来的属性和方法,可以看到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);
             })

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


当然我们可以直接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);
             })

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

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

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

这个方法的使用场景很多,比如可以用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方法,显示图片请求超时。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95098.html

相关文章

  • JavaScript Promises 体验

    摘要:回调函数是的一大特色官方的基本都是以会回调方式传递函数返回值。针对这种普遍问题,应势而生基本用法创建做一些异步操作的事情,然后一切正常的构造器接受一个函数作为参数,它会传递给这个回调函数两个变量和。 Promise 是什么? Promise 对象用来进行延迟(deferred) 和 异步(asynchronous) 计算。 一个 Promise 处于以下三种状态之一: pend...

    Baoyuan 评论0 收藏0
  • Service Workers (PWA 体验

    摘要:是一个注册在指定源和路径下的事件驱动。可以提供有效有效的离线体验,拦截网络请求。出于安全原因,要求必须在下才能运行。返回一个对象,的结果是对象值对象组成的数组。当事件的处理程序执行完毕后,可以认为安装完成了。 在前端越来越重的这个时代,页面加载速度成为了一个重要的指标。对于这个问题,业界也有一些解决方案。 浏览器缓存、协议缓存、强缓存 懒加载(首屏) CDN 多域名突破下载并发限制。...

    twohappy 评论0 收藏0
  • Service Workers (PWA 体验

    摘要:是一个注册在指定源和路径下的事件驱动。可以提供有效有效的离线体验,拦截网络请求。出于安全原因,要求必须在下才能运行。返回一个对象,的结果是对象值对象组成的数组。当事件的处理程序执行完毕后,可以认为安装完成了。 在前端越来越重的这个时代,页面加载速度成为了一个重要的指标。对于这个问题,业界也有一些解决方案。 浏览器缓存、协议缓存、强缓存 懒加载(首屏) CDN 多域名突破下载并发限制。...

    刘厚水 评论0 收藏0
  • 新手的node爬虫体验

    摘要:后来在爬取不到让我一度怀疑人生的时候巧合下,发现磁力链接有小写字母,有长度的,有长度的。。 原文博客: 羞羞的node爬虫 前言 学了一阵子node,除了用 express 写东西,就没怎么做过东西突然就想写个 爬虫 来玩一玩,而且还是爬一些羞羞的东西 使用模块 SuperAgent 是个 http 方面的库,可以发起 get 或 post 请求。 cheerio 大家可以理解成一个 ...

    wemallshop 评论0 收藏0

发表评论

0条评论

leap_frog

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<