Promise入门指导

Promise讲解

15年6月份,ES2015正式发布,其中Promise被列为正式规范,而且作为ES6中最重要的特性之一,我们有必要掌握并理解透彻。本文将会讲解Promise的基本概念与使用方法。

什么是Promise

Promise是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和强大。
其实,Promise是一个对象,它可以获取异步操作的数据。

Promise有两个特点:
1。对象的状态不受外界干扰,Promise对象代表一个异步操作,他有三种状态,pending(等待,进行中),resolved(已完成),reject(已失败)。
只有异步操作的结果能决定它的状态,而且一旦决定将无法改变,这也是这是Promise名字的由来—–承诺。

2。Promise的状态只能从pending变成resolved或从pending变成rejected
一旦改变就不可更改。

有了Promise对象,我们就可以吧异步操作以同步操作的流程表达出来了,避免了层层嵌套的回调函数,此外,Promise对象提供了统一的接口,使得控制异步操作更加容易。

基本用法

首先,啥也不说,先打印一下Promise看看吧:
Promise

这么一看就明白很多了,promise其实就是一个构造函数,他里面又很多方法,例如all(),race(),reject(),resolve(),它的原型中还有then()和catch()

创建一个Promise实例也很简单,他接受一个函数作为参数,这个函数有接受两个参数,分别为resolve和reject这两个也是函数,分别是在异步操作成功和失败时调用的:

var p = new Promise(functionresolvereject){
   if(异步操作成功){
     resolve();
   }else{
     reject():
   }   
})

以延时操作为例:

var p1 = new Promise(function(resolve,reject){
   setTimeOut(function(){
    console.log("执行完成");
    resolve("延时执行完成");
  },1000)
})
console.log("我是外部操作")


//我是外部操作
//执行完成

上面的代码中,我们执行了一个异步操作,也就是setTimeout,先执行外部操作,然后1秒后,输出“执行完成”,并调用resolve()方法 ,我们能发现,在上面的代码中我们只是new 了一个对象 并没有去调用他,但是函数已经执行了,这就是我们要注意的一个问题。所以我们在用Promise时都是把它包在一个函数中,在需要的时候去调用这个函数。

function run(){
  var p1 = new Promise(function(resolve,reject){
   setTimeOut(function(){
    console.log("执行完成");
    resolve("延时执行完成");
  },1000)
}) 
    return p1;
}

run();

我们包装好的函数会返回一个Promise的对象。也就是说执行这个函数能得到一个Promise对象,而前面我们也看到了,Promise对象有then和catch方法。

接下来,我么就可以去处理异步操作完成之后的事情了。

run().then(function(data){
  console.log(data);
})

then接受一个参数,是函数,并且会拿到我们调用resolve中时传入的参数,运行上面的代码后,会在输出 “执行完成”后紧接着输出“延时执行完成”。
其实这是我们就能发现了,then里面的函数就和我们平时用的回调函数是一个意思,简单的讲就是把原来的回调函数写法分离出来,能使用链式调用的方法来执行回调函数。

那么这时也许有人就要问了,既然效果是一样的,为什么还要用Promise呢。

链式操作

其实Promise的主要用处是来处理多重嵌套的回调函数。
以前的写法遇到回调函数也是一个异步操作时,会特别麻烦,我们要在这个回调函数(callback)执行完之后也要有相应的回调函数,又要定义一个callback2 以此类推。
而使用Promise,我么可以直接在then后面接着写多层嵌套,使用链式的写法来进行回调操作。

例:我定义了三个Promise

function run (){
  var p1 = new Promise(function(resolve,reject){
    setTimeout(function(){
      console.log("第一次函数执行");
      resolve("第一次调用成功!");
    },1000)
  })
 return p1;
}
function run2 (){
  var p2 = new Promise(function(resolve,reject){
    setTimeout(function(){
      console.log("第二次函数执行");
      resolve("第二次调用成功!");
    },2000)
  })
 return p2;
}
function run3 (){
  var p3 = new Promise(function(resolve,reject){
    setTimeout(function(){
      console.log("第三次函数执行");
      resolve("第三次调用成功!");
    },500)
  })
 return p3;
}

现在我要一次去执行他们,我想要在run()执行完之后执行run2 ,然后再执行run3:

run().then(function(data){
  console.log(data);
  return run2();
}).then(function(data){
   console.log(data);
return run3();
 }).then(function(data){
   console.log(data);
})

这样就能很轻松的使用多层嵌套。

all方法

还是以上面的三个Promise为例:
现在我想要在这三个方法都只需完之后再去执行某些操作,这时就需要用到all方法了。
all方法接受一个Promise的数组

Promise.all([run(),run1(),run2()]).then(function(data){
  console.log(data);
});

//第三次函数执行
//第一次函数执行
//第二次函数执行
//[“第一次调用成功”,“第二次调用成功”,“第三次调用成功”]

此时的三个异步操作,并行执行,但是直到三个操作都完成后才会执行,最后的“console.log(data)”这里的data包含了三次异步操作返回的结果。

这个方法可以用到游戏类页面上,直到所有素材都加载完之后,进行页面的初始化。

race方法

race方法与all方法相反,all方法是直到所有异步操作都返回时,执行后续操作,
而race方法则是看谁先执行完,就直接操作后续操作。
还是以上面三个Promise为例:

Promise.race([run(),run2(),run3()]).then(function(data){
  console.log(data);
})

//第三次函数执行
//第三次调用成功
//第一次函数执行
//第二次函数执行

在run3完成后就会执行console.log(data),当然这时的data只有run()返回的结果。但是此时的run和run3不会停止,还是会执行。

这个方法的使用场景还是很多的。例如图片加载:

function loadImg(){
  var p = new Promise(function(resolve,reject){
   var img = new Image();
   img.src = 'sad';
   img.onload = function(){
     resolve("加载完成"); //当执行完这个异步函数时返回成功
   }
 })
}

function timeOut(){
  var p = Promise(resolve,reject){
   setTimeout(function(){
     reject('图片加载失败');//当执行完这个函数时返回失败
   },1000)
 }
}

Promise.race([loadImg(),tiemOut()]).then(function(data){
  console.log(data);//当返回为成功时执行这条语句
},function(err){
  console.log(err);//当返回为失败时执行这条语句
})

//图片加载失败

结果是会在1秒之后输出图片加载失败,因为我们给的是一个无效的src,肯定无法成功请求到,timeOut是一个延时3秒的异步操作,把这两个异步操作放到race方法中,他们会竞赛,如果三秒内图片没有请求成功,那么timeOut就会跑赢了,会返回他的执行完之后的结果,也就是reject(”图片加载失败”);

上面我们的例子都是使用setTimeout这个方法来实现异步操作,但是我相信我们平常用的最多的肯定是ajax的异步操作,promise的用法在ajax中也是一样的。

//创建一个Promise实例,获取数据。并把数据传递给处理函数resolve和reject。需要注意的是Promise在声明的时候就执行了。
var getUserInfo=new Promise(function(resolve,reject){
    $.ajax({
        type:"get",
        url:"index.aspx",
        success:function(data){
            if(data.Status=="1"){
                resolve(data.ResultJson)//在异步操作成功时调用
            }else{
                reject(data.ErrMsg);//在异步操作失败时调用
            }
        }
    });
})
//另一个ajax Promise对象,
var getDataList=new Promise(function(resolve,reject){
    $.ajax({
        type:"get",
        url:"index.aspx",
        success:function(data){
            if(data.Status=="1"){
                resolve(data.ResultJson)//在异步操作成功时调用
            }else{
                reject(data.ErrMsg);//在异步操作失败时调用
            }
        }
    });
})
//Promise的方法then,catch方法
getUserInfo.then(function(ResultJson){
    //通过拿到的数据渲染页面
}).catch(function(ErrMsg){
    //获取数据失败时的处理逻辑
})
//Promise的all方法,等数组中的所有promise对象都完成执行
Promise.all([getUserInfo,getDataList]).then(function([ResultJson1,ResultJson2]){
    //这里写等这两个ajax都成功返回数据才执行的业务逻辑
})

好了,本次的Promise的讲解就先到这了,希望能帮到一些小伙伴哦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值