资讯专栏INFORMATION COLUMN

Promise使用须知

Tikitoo / 1834人阅读

摘要:已完成意味着操作成功完成。处理实例实例生成以后,可以用方法分别指定状态和状态的回调函数。第二个回调函数在的状态变成时被调用。方法是的别名,用于指定发生错误时的回调函数。具体的使用示例如下情形一全部成功的情况结果为。

一.关于Promise

promise 是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

它代表一个异步操作。有三种状态:

pending(进行中): 初始状态, 初始状态,未完成或拒绝。

resolved(已完成): 意味着操作成功完成。又名fulfilled

rejected(已失败): 意味着操作失败。

有了Promise,就可以将异步操作以同步操作的流程表达出,但它也有如下缺点

一旦创建它就会立即执行,无法中途取消。

如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

二.应用示例 1. 创建Promise
var promise = new Promise(
    /* executor */ 
    function(resolve, reject){
        ...
    }
);

​ executor函数由Promise实现立即执行,传递resolve和reject函数. (在Promise构造函数之前调用执行器甚至返回创建的对象)

​ 在 executor 内部,promise有如下的状态变化可能:

​ 1. resolve被调用,promise由pending变为resolved,代表该Promise被成功解析(resolve)

​ 2.reject 被调用,promise由pending变为rejected,代表该Promise的值不能用于后续处理,即被拒绝了

注意:

如果在executor 方法的执行过程中抛出了任何异常,那么promise立即被拒绝(即相当于reject方法被调用),executor 的返回值也就会被忽略。

如果一个promise对象处在resolvedrejected状态而不是pending状态,那么它也可以被称为settled状态。

2.处理Promise实例

then:Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。

promise.then(function(value) {
  // success 状态为Resolved时调用
}, function(error) {  
  // failure 状态为Reject时调用
});

then方法可以接受两个回调函数作为参数。

第一个回调函数:在promise的状态变成resolved时被调用。它的参数promise的resolve方法的返回值。

第二个回调函数:在promise的状态变成rejected时被调用。它的参数promise的reject方法的返回值。且为可选参数。

catchPromise.prototype.catch方法是.then(null, rejection)的别名,用于指定发生错误时的回调函数

promise.then(function(posts) {
  // ...
}).catch(function(error) {
  console.log("发生错误!", error); // 处理 promise 和 前一个回调函数运行时发生的错误
});

扩展:

Promise.prototype.then和 Promise.prototype.catch方法返回 promises对象, 所以它们可以被链式调用。但此时返回的是以函数返回值生成的新的Promise实例,不是原来那个Promise实例

注意问题:

Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。

3.将多个Promise实例,包装成一个新的Promise实例

Promise.all(iterable) :当所有在可迭代参数中的 promises 已完成,或者第一个传递的 promise(指 reject)失败时,返回 promise。

var p = Promise.all([p1, p2, p3]);

当p1、p2和p3的状态均为resolved时p的状态为resolved

当p1、p2或p3中的任意一个被rejectedp的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。

具体的使用示例如下:

情形一:全部成功的情况

Promise.all([Promise.resolve("foo"),Promise.resolve("bar"),Promise.resolve("test")])
  .then(function(result){
            console.log(result); //结果为:[foo,bar,test]。即所有返回值的数组。
         })
   .catch(function(error) {
           console.log("error");    //不会被执行
   });

情形二:全部失败或部分失败

Promise.all([Promise.resolve("foo"),Promise.reject("barError"),Promise.reject("testError")])
   .then(function(result){
            console.log(result);            //成功回调  不会被执行
         })
   .catch(function(error) {
           console.log(error);    //结果为barError或testError。即第一个被reject的值。
   });

三.常见的使用误区

忘记添加 .catch()

通常情况,promise有如下两种处理方式:

// ------------    不好的写法   -------------
promise.then(function(data) {
    // success
  }, function(err) {   //仅处理promise运行时发生的错误。无法处理回调中的错误
    // error
  });

// ------------    好的写法    ------------
promise.then(function(data) {
    // success
}).catch(function(err) {   // 处理 promise 和 前一个回调函数运行时发生的错误
    // error 
});

因为promise抛出的错误不会传递到外层代码。当使用没有catch的第一种种写法时,成功回调的错误将无法被处理。因此比较好的方式是,总是使用catch方法。

在then或者catch函数中不使用return

下面是在是用Promise时,一个很常见的错误写法:

//------------    不好的写法    ------------------
promise.then(function () {
  getUserInfo(userId);
}).then(function () {
  // 在这里可能希望在这个回调中使用用户信息,但你可能会发现它根本不存在
});

会发生上面的错误,是因为对Promise的返回及链式调用的理解不够。

每一个promise都会给你一个then()方法(或者catch,它们只是then(null,…)的语法糖)。这里我们是在then()方法的内部来看:

promise.then(function () {
  return getUserInfo(userId);
}).then(function (userInfo) {
   HadleUser(userInfo);
}).catch(function(error) {
   console.log(error);
});

在回调中在有三种事可以做:

返回另一个promise

如果getUserInfo返回一个Promise,则HadleUser将在该promise变为resolved后执行,并以该promise的返回作为入参。

返回一个同步值(或者undefined)

getUserInfo返回一个同步值,则改值会被包装成一个resolved状态的promise,HadleUser将被立刻执行,并以getUserInfo返回作为入参。

抛出一个同步错误

getUserInfo返回一个同步错误,则该错误会被包装成一个rejected状态的promise,最终在catch中被捕获。此时HadleUser将不会被执行。

promises丢失

你认为下面的代码会打印出什么?

Promise.resolve("foo").then(Promise.resolve("bar")).then(function (result) {
  console.log(result);
});

如果你认为打印出bar,那你就大错特错了。它实际上会打印出foo。

原因是当你给then()传递一个非函数(比如一个promise)值的时候,它实际上会解释为then(null),这会导致之前的promise的结果丢失。

四.最佳实践总结

then方法中 永远 return 或 throw

如果 promise 链中可能出现错误,一定添加 catch

永远传递函数给 then 方法

不要把 promise 写成嵌套

参考链接:

Promise -JavaScript | MDN

Promises 很酷,但很多人并没有理解就在用了

Promise 对象

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

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

相关文章

  • 【容器实例 Cube】使用须知:秒级拉起您的业务容器提供服务

    摘要:使用依赖请预先创建好和子网如果是需要绑定,请预先给操作账号赋予网络相关权限需要使用到镜像仓库,需要创建并将镜像上传。实时文档欢迎访问使用须知使用须知使用Cube服务,必须通过UCloud实名认证服务;使用Cube暴露公网服务,请与UCloud备案团队联系进行备案,否则可能会影响您的服务正常使用;您的业务程序已经完成容器化,已有Docker镜像;您创建的Cube实例,将默认镜像拉取策略为总是(...

    Tecode 评论0 收藏0
  • 数据接口(API)开发须知

    摘要:由服务端生成在请求任何接口之前,都必须先请求一个获取服务器生成的的接口,获取之后,才请求其他接口是请求时间型号设备号系统类型加密加密头部存储基本参数加密校验参数必须填必须填以下为选填,可有可无,任由开发者自己定义类型设备号版本型号 传统API与RESTful API 传统API 获取用户信息 get /api/user/read 更新用户信息 post /api/user/u...

    piglei 评论0 收藏0
  • Vert.x入坑须知(3)

    摘要:对于集成测试,直接模拟实际的环境,再加上合适的,目前看来也还不错。这里给出两个例子集成测试单元测试都是基于写的,各位可以体验其酸爽度。好啦,本期内容就此结束,请保持关注,期待下期继续本系列其他文章入坑须知入坑须知 随着Vert.x进化到3.5.0,本系列也迎来了新篇章。 CORS的新变化 对于CORS,搞Web开发(不论你是前端,还是后端)的同志应该不陌生,尤其是如今微服务盛行的时代,...

    CollinPeng 评论0 收藏0
  • Vert.x入坑须知(4)

    摘要:主要是避免引入太多的复杂性,并且出于灵活部署的需要。以应用为例,由于实际上是在上执行,若它被阻塞,即导致后续请求全部无法得到处理。因此,最合适的做法就是对于简单业务,采用异步库。本系列其他文章入坑须知入坑须知入坑须知 最开始觉得这个系列也就最多3篇了不起了(因为事不过三嘛),没曾想居然迎来了第四篇! Kotlin 由于最近决定投身到区块链的学习当中的缘故,出于更好的理解它的基本概念,自...

    summerpxy 评论0 收藏0

发表评论

0条评论

Tikitoo

|高级讲师

TA的文章

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