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传入的参数dom

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方法就能够直接接收到数据,以下:spa

// 正确的打开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的回调。code

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方法,显示图片请求超时。

请求超时的结果

正确的请求的结果

相关文章
相关标签/搜索