Promise使用须知

一.关于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对象处在resolved或rejected状态而不是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方法的返回值。且为可选参数。
catch:Promise.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实例。[图片上传中。。。(1)]

注意问题:
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中的任意一个被rejected,p的状态就变成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 对象

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,107评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • 我就是想把老破电脑上下载的权利的游戏拉下来到ipad上看啊喂,该死的ipad各种不支持,我又不想在装itunes,...
    marine0131阅读 5,165评论 0 0
  • 商业模式:并非单纯的盈利模式,包括成本分析、营收周期、盈利模式几个方面。闭环思维:从竞品出发发现用户痛点,并提出解...
    生活鸽子阅读 141评论 0 0
  • 今天,2015年12月30日。一向爱刷微博的我,一如既往的 ,早晨起床先刷微博,关注热搜娱乐程度高于任何热点大事。...
    Karain_Wong阅读 321评论 0 0