加载中...

关于Promise的使用与总结

吴佳
2019-01-31 15:12:13
分类:JavaScript
2834
8
0

说起JS大家都知道是单线程的,对于早期Promise还没诞生的时候处理异步都是通过回调函数处理的,层层嵌套的回调会让代码失去美感和可读性,同时JAVASCRIPT也推荐采用链式的方式去书写函数调用,于是Promise就应运而生。

Promise顾名思义即承诺的意思,new一个Promise可以说就是新建一个承诺。在新建一个承诺的时候你需要做两件事情:

  1. 指定承诺所需完成的事
  2. 设置承诺是否实现的标准

在ECMAscript2015版本,即大家常听说或常用的ES6中,Promise是一个构造函数,对回调函数的一种封装,对异步编程的一种改进,即一个或多个异步处理用同步的方式表达出来。该构造函数身上有两个常用方法:Promise.all(),Promise.race()。

上方说到实例(new)一个Promise就是新建一个承诺并要做两件事情,下面用代码来解释一下:
承诺的内容是:“ajax获取的数据 ”
承诺是否实现的评判是:“是否获取当前ajax请求的数据 ”

new Promise(function(resolve, reject) {
    ajax({
        url: '...',
        success: function(res) {
            resolve(res);
        },
        error: function(err) {
            reject(err);
        }
    })
}).then(function(res) {
    //得到数据
}).catch(function(err) {
    //出现异常
});

这里解释一下上方代码,我们在实例化(new)一个Promise时,可传递一个回调函数作为参数,回调函数可接受两个形参即:resolve,reject。然后将ajax异步请求放置在回调函数内部进行请求,这里我需要先解释一下两个形参:

resolve : 它是一个函数,其用意是,如果执行resolve函数即代表完成当前异步的处理并通过传递一个参数将数据传递进去,这时链式调用的then回调会立即执行并接受一个回调函数,回调函数有一个形参用来接受resolve执行传递过来的数据。resolve的执行可传递一个参数,参数可是各数据类型,也可以接受一个新的Promise对象,如果resolve执行没有传递数据那么then的回调函数的形参值即是Undefined。

reject:它也是一个函数,其用意是,如果执行reject函数即代表拒绝当前异步处理,它的执行说明发生了异常,并也通过传递一个参数将异常信息传递进去,这时链式调用的catch回调会立即执行并接受一个回调函数,回调函数有一个形参用来接受reject执行传递过来的异常信息。reject的执行可传递一个参数,参数可是各数据类型,也可以接受一个新的Promise对象,如果reject执行没有传递数据那么catch的回调函数的形参值即是Undefined。

解释完两个参数,这里需要提两个关键字出来:‘完成’和‘拒绝(异常)’。其实新建一个实例(new)Promise会有三种状态:等待(pending),完成(resolve),拒绝(reject);上方已经解释了‘完成’和‘拒绝’状态,这里再给说一下等待的状态,其实初始化的时候就是等待状态,当resolve或reject执行的时候就会更新为对应状态,如果两者都没执行即会一直等待。

说到这里需要再说一下then这个回调函数,上方已经解释当resolve函数执行时即完成时,就会立即执行then的回调函数,then回调函数其实可以接受两个参数,即对应于resolve完成状态和reject拒绝状态,这两个参数都是回调函数用来接受对应状态传递过来的数据信息。当然then的回调内部可以继续return一个新的Promise对象,这样既会形成一个多层的异步处理,下方用代码理解一下:

new Promise(function(resolve, reject) {
    ajax({
        url: '...',
        success: function(res) {
            resolve(res);
        },
        error: function(err) {
            reject(err);
        }
    })
}).then(function(res) {
//得到数据
return new Promise(function(resolve,reject) {
ajax({
url: "...",
success: function(res) {
resolve(res);
},
error: function(err) {
reject(err)
}
});
})
}).then(function(res){
//得到上一个then返回的新Promise处理完成后的数据

.... 这里就省略了
}).catch(function(err) {
//出现异常
});

经上方代码,我们可以很清楚的明白,我们能以此内推每层返回一个新的Promise,这样一来我们就能解决多个异步请求能够以同步的形式表达出来,可以说这样是可以无限的循环 ...;但是,这里有一个注意点:
链式调用catch与then的第二参数reject回调函数的区别,就最上方代码进行改造来做理解:

链式调用catch情况

new Promise(function(resolve, reject) {
    ajax({
        url: '...',
        success: function(res) {
            resolve(res);
        },
        error: function(err) {
            reject(err);
        }
    })

     假如在这里业务逻辑出现异常
}).then(function(res) {
//得到数据
或者在这里业务逻辑出现异常
}).catch(function(err) {
 那么就会触发这里异常回调
});

then的第二参数reject回调

new Promise(function(resolve, reject) {
    ajax({
        url: '...',
        success: function(res) {
            resolve(res);
        },
        error: function(err) {
            reject(err);
        }
    })
        假如在这里业务逻辑出现异常
}).then(function(res) {
//得到数据
或者这里业务逻辑出现异常
},function(err) {
则不会执行此处错误回调
});

我们就上方代码可以很清楚的看到几个大红字,然而这就是两者写法的一个区别,也就是说如果我们在Promise的回调函数或then的回调里面发生了异常,那么如果后面紧跟了catch的链式回调就会立即执行。因为不管是Promise回调出现异常还是then的回调函数内出现异常,是都不会中断后续代码的执行,即发生异常就会自动触发catch的执行。

如果是then传入第二参数reject回调的话,这就大不一样了,这样触发当前这个参数执行的条件就是在实例化(new)Promise的时候,只有当状态更新为拒绝时,即reject函数执行时,才会触发then第二参数reject回调函数的执行并接受异常信息数据;如果多层异步处理,那么每一个then的第二参数reject回调都会对应上一层Promise的reject执行状态。

到这,已经说完了Promise的使用和注意的地方,现在我们说说常用的两个方法:

Promise.all():它是 Promise 对象上的静态方法,该方法的作用是将多个 Promise 对象实例包装,生成并返回一个新的 Promise 实例。接收一个 Promise 对象的数组作为参数,当这个数组里的所有 Promise 对象全部变为 resolve(完成) 状态的时候,它才会去调用 .then 方法,它们是并发执行的。如果执行中任意一个Promise状态是reject(拒绝)时,就会调用 .catch 方法。

Promise.race(): 它也是 Promise 对象上的静态方法,顾名思义英语比较好的同学都知道race代表赛跑,比赛的意思。所以与all不同的是,当数组里的所有Promise对象,谁的执行速度快就返回该对象的结果,无论是完成状态还是拒绝状态。

扫码关注后,回复“资源”免费领取全套视频教程

前端技术专栏

8

发表评论(共0条评论)

请输入评论内容
啊哦,暂无评论数据~