用Promise讲一个悲伤的故事给你听

开发 前端
那天我正在学习 Promise,突然家里打电话过来说,家里盖房子要钱。我工作这么多年了,从事着别人眼中高薪工作,于是满口答应下来。但是由于我并没有钱,于是我跟家里说,等过几天我再打钱过去。我也好乘着这几天想想办法。

[[234989]]

那天我正在学习 Promise,突然家里打电话过来说,家里盖房子要钱。我工作这么多年了,从事着别人眼中高薪工作,于是满口答应下来。但是由于我并没有钱,于是我跟家里说,等过几天我再打钱过去。我也好乘着这几天想想办法。

首先我找到我的同学李雷,他现在一个部门经理了,我想应该他应该有钱。我跟他说明了借钱的意向,李雷二话不说就答应借我300,不过同时表示要回家跟老婆商量商量,我说好。此时我想起来答应或者说承诺的英文单词就是 Promise 。承诺的结果是钱,钱是数值(number 类型)。于是我想把我要借钱的这一行为写成一个 TypeScript 函数如下:

 

  1. // 向李雷借钱,李雷丢给我一个承诺 
  2. function borrowMoneyFromLiLei(): Promise<number> { 
  3.   return new Promise<number>(function(fulfill, reject) { 
  4.      // 李雷跟老婆商量中 
  5.   }); 

此时,我在想李雷老婆会答应给我借300块吗?我不确定,就像薛定谔的猫。借还是不借,这是一个问题。然后我发现这也可以写成一个函数。借或者不借用布尔值来表示 (boolean 类型)。函数如下:

 

  1. // 李雷的老婆是否会答应给我借钱? 
  2. function willLiLeiWifeLendMeMoeny(): Promise<boolean> { 
  3.   return new Promise<boolean>(function(lend, reject) { 
  4.     // 借还是不借 
  5.   }); 

如果李雷借我钱了,我就转钱给家里,没有,我应该要再去找别人借了。可以用下面的函数描述我此时的处境。

 

  1. function transferMoneyToHome(money: number) { 
  2.     // 给家里转钱 
  3. function mySituation(){ 
  4.     borrowMoneyFromLiLei() 
  5.     .then((money:number) => { 
  6.         // 如果李雷借我钱了,我就转钱给家里. 
  7.         transferMoneyToHome(money) 
  8.     }).catch((reason) => { 
  9.         // 李雷老婆拒绝借钱给我。 那我应该考虑向其他人借了。 
  10.         borrowMoneyFromOthers() 
  11.     }) 

找其他人借,我能想到就(张三,李四,五五)这三个人了,其他的朋友很少联系,突然说借钱也不好。于是我尝试向他们借钱。用代码表示是这样子的:

  1. function borrowMoneyFromOthers() { 
  2.   // 我先试着向张三借 
  3.   tryBorrowMoneyFromZhangshan() 
  4.     .then(money => { 
  5.       transferMoneyToHome(money); 
  6.     }) 
  7.     .catch(reason => { 
  8.       // 如果张三不借,并丢给我一个理由 
  9.       // 试着向李四借 
  10.       tryBorrowMoneyFromLisi() 
  11.         .then(money => { 
  12.           transferMoneyToHome(money); 
  13.         }) 
  14.         .catch(reason2 => { 
  15.           // 如果 李四也不肯错 
  16.           // 再试试向王五借 
  17.           tryBorrowMoneyFromWangwu() 
  18.             .then(money => { 
  19.               transferMoneyToHome(money); 
  20.             }) 
  21.             .catch(reason => { 
  22.               // 没有人肯借 
  23.               throw new Error("我该怎么办呢?"); 
  24.             }); 
  25.         }); 
  26.     }); 

由于借着钱之后都是向家里转钱,所以上面的代码应该简化一下。简化后如下:

 

  1. function borrowMoneyFromOthers() { 
  2.   // 我先试着向张三借 
  3.   tryBorrowMoneyFromZhangshan() 
  4.     .then(transferMoneyToHome) 
  5.     .catch(reason => { 
  6.       // 如果张三不借,并丢给我一个理由 
  7.       // 试着向李四借 
  8.       tryBorrowMoneyFromLisi() 
  9.         .then(transferMoneyToHome) 
  10.         .catch(reason2 => { 
  11.           // 如果 李四也不肯错 
  12.           // 再试试向王五借 
  13.           tryBorrowMoneyFromWangwu() 
  14.             .then(transferMoneyToHome) 
  15.             .catch(reason => { 
  16.               // 没有人肯借 
  17.               throw new Error("我该怎么办呢?"); 
  18.             }); 
  19.         }); 
  20.     }); 

在上面的思路中,我是一个一个找他们借钱的,一个借不着再找另一个。我为什么不同时找他们借呢?谁借我了,我就转钱给家里。此时我想起了刚学的 Promise.race 方法,也许这个方法可以帮助我表达我的这一决策需求.

 

  1. function borrowMoneyFromOthers() { 
  2.   // 同时向张三,李四,王五借钱,只要有人借我钱了,我就转钱给家里。 
  3.   Promise.race([ 
  4.     tryBorrowMoneyFromZhangshan(), 
  5.     tryBorrowMoneyFromLisi(), 
  6.     tryBorrowMoneyFromWangwu() 
  7.   ]) 
  8.     .then(transferMoneyToHome) 
  9.     .catch(reasons => { 
  10.       console.warn("没一个人愿意给我借钱,他们理由是:", reasons); 
  11.     }); 

我用timeout 模拟一下他们给我答复的,代码如下:

 

  1. // 尝试找张三借 
  2. function tryBorrowMoneyFromZhangshan(): Promise<number> { 
  3.   return new Promise(function(fulfill, reject) { 
  4.     setTimeout(() => { 
  5.       fulfill(300); 
  6.     }, 100); 
  7.   }); 
  8. // 尝试找李四借 
  9. function tryBorrowMoneyFromLisi(): Promise<number> { 
  10.   return new Promise(function(fulfill, reject) { 
  11.     setTimeout(() => { 
  12.       reject("对不起我也没钱"); 
  13.     }, 50); 
  14.   }); 
  15. // 尝试找王五借 
  16. function tryBorrowMoneyFromWangwu(): Promise<number> { 
  17.   return new Promise(function(fulfill, reject) { 
  18.     setTimeout(() => { 
  19.       fulfill(300); 
  20.     }, 500); 
  21.   }); 

结果运行之后,控制台输出的是:

没一个人愿意给我借钱,他们理由是: 对不起我也没钱

看来 Promise.race 适用用来模拟抢答,而不是选择最优解。 比如多人抢答一个问题,第一个抢答之后不论他回答的是否是正确,这个题都过了。

不过没关系。也许我可以自己写一个来叫做 promiseOne 的函数来实现这个功能。代码如下:

 

  1. /** 
  2.  * 当其中一个 Promise 兑现时,返回的 Promise 即被兑现 
  3.  * @param promises Promise<T> 的数组 
  4.  */ 
  5. function promiseOne<T>(promises: Promise<T>[]): Promise<T> { 
  6.   const promiseCount = promises.length; 
  7.   return new Promise<T>(function(resolve, reject) { 
  8.     const reasons: any[] = []; 
  9.     let rejectedCount = 0; 
  10.     promises.forEach((promise, index) => { 
  11.       promise.then(resolve).catch(reason => { 
  12.         reasons[index] = reason; 
  13.         rejectedCount++; 
  14.         if (rejectedCount === promiseCount) { 
  15.           reject(reasons); 
  16.         } 
  17.       }); 
  18.     }); 
  19.   }); 

正当我写完了上面的代码,他们三个给我回话了,说是现在手上也没有那么多钱,但是可以给我借100. 于是我现在需要处理这样的事情,就是当他们三个人把钱都转给我之后我再转给家里。 当他们三个都兑换借我100块钱的承诺时,可以用 Promise.all 来表示,代码如下:

 

  1. function borrowMoneyFromOthers() { 
  2.   // 同时向张三,李四,王五借钱, 借到之后,我就转钱给家里。 
  3.   Promise.all([ 
  4.     tryBorrowMoneyFromZhangshan(), 
  5.     tryBorrowMoneyFromLisi(), 
  6.     tryBorrowMoneyFromWangwu() 
  7.   ]) 
  8.     .then(moneyArray => { 
  9.       console.info("借到钱啦:", moneyArray); 
  10.       const totalMoney = moneyArray.reduce((acc, cur) => acc + cur); 
  11.       transferMoneyToHome(totalMoney); 
  12.     }) 
  13.     .catch(reasons => { 
  14.       console.warn("有人不愿意给我借钱,理由是:", reasons); 
  15.     }); 

现在有三个人愿意给我借钱了,嗯,也就是说我借到了 300 块。然而这钱用来建房还是杯水车薪。所以我还得想办法。我想我要不要试试用这300块来买一下彩票。如果中了,说不定这事就成了。

 

  1. function buyLottery(bet: number): Promise<number> { 
  2.   return new Promise(function(fulfill, resolve) { 
  3.     // 投注 
  4.     // 等待开奖 
  5.     setTimeout(() => { 
  6.       resolve("很遗憾你没有买中"); 
  7.     }, 100); 
  8.   }); 
  9.  
  10. function borrowMoneyFromOthers() { 
  11.   // 同时向张三,李四,王五借钱,  
  12.   Promise.all([ 
  13.     tryBorrowMoneyFromZhangshan(), 
  14.     tryBorrowMoneyFromLisi(), 
  15.     tryBorrowMoneyFromWangwu() 
  16.   ]) 
  17.     .then(moneyArray => { 
  18.       console.info("借到钱啦:", moneyArray); 
  19.       const totalMoney = moneyArray.reduce((acc, cur) => acc + cur); 
  20.       // 购买彩票 
  21.       buyLottery(totalMoney) 
  22.         .then(transferMoneyToHome) 
  23.         .catch(reason => { 
  24.           console.log("没中,", reason); 
  25.         }); 
  26.     }) 
  27.     .catch(reasons => { 
  28.       console.warn("有人不愿意给我借钱,理由是:", reasons); 
  29.     }); 

我知道很大概率我是买不中的,最近世界杯开赛了,我幻想着压注世界杯,而且世界杯场次多,一天好几场,一场买中的盈利还可以投入到下一场。我把我的幻想写成代码,大概就是下面这样。

 

  1. function betWorldCup() { 
  2.   // 初始资金 300 块 
  3.   Promise.resolve(300) 
  4.     .then(moeny => { 
  5.       // 投西班牙 
  6.       return new Promise<number>(function(fulfil, reject) { 
  7.         setTimeout(() => { 
  8.           // 假假设 赔率 1.2 
  9.           fulfil(moeny * 1.2); 
  10.         }, 100); 
  11.       }); 
  12.     }) 
  13.     .then(ret => { 
  14.       // 投英格兰 
  15.       return ret * 1.2; 
  16.     }) 
  17.     .then(ret => { 
  18.       // 投巴西 
  19.       return new Promise<number>(function(fulfil, reject) { 
  20.         setTimeout(() => { 
  21.           fulfil(ret * 1.2); 
  22.         }, 92); 
  23.       }); 
  24.     }) 
  25.     .then(ret => { 
  26.       console.log("现在收益加本金共有: ", ret); 
  27.     }); 

我想,如果第一场投失败了,应该再给自己一次机会。于是将代码修改如下:

 

  1. function betWorldCup() { 
  2.   // 初始资金 300 块 
  3.   Promise.resolve(300) 
  4.     .then(moeny => { 
  5.       // 投西班牙 
  6.       return new Promise<number>(function(fulfil, reject) { 
  7.         setTimeout(() => { 
  8.           // 假假设 赔率 1.2 
  9.           // fulfil(moeny * 1.2); 
  10.           reject("庄家跑跑路了"); 
  11.         }, 100); 
  12.       }); 
  13.     }) 
  14.     .then
  15.       ret => { 
  16.         // 投英格兰 
  17.         return ret * 1.2; 
  18.       }, 
  19.       reason => { 
  20.         console.info("第一次投注失败,再给一次机会好不好?, 失败原因: ", reason); 
  21.         // 再投 300 
  22.         return 300; 
  23.       } 
  24.     ) 
  25.     .then(ret => { 
  26.       // 投巴西 
  27.       return new Promise<number>(function(fulfil, reject) { 
  28.         setTimeout(() => { 
  29.           fulfil(ret * 1.2); 
  30.         }, 92); 
  31.       }); 
  32.     }) 
  33.     .then(ret => { 
  34.       console.log("现在收益加本金共有: ", ret); 
  35.       throw new Error("不要再买了"); 
  36.     }) 
  37.     .then(ret => { 
  38.       console.info("准备再买吗?"); 
  39.     }) 
  40.     .catch(reason => { 
  41.       console.log("出错了:", reason); 
  42.     }); 

此时如下运行上面的函数会得到如下输出:

  • 第一次投注失败,再给一次机会好不好?, 失败原因: 庄家跑跑路了
  • 现在收益加本金共有: 360
  • 出错了:
  • Error: 不要再买了

然而,幻想结束之后,我依然得苦苦思考怎么样筹钱。

责任编辑:未丽燕 来源: 程序师
相关推荐

2018-06-23 08:02:31

程序员代码故事

2015-08-13 14:35:43

2022-12-22 08:22:17

Python图像图像处理

2015-11-12 09:47:28

2015-08-05 09:45:25

IOS故事多线程

2024-01-08 13:40:00

并发安全• 数量

2015-11-06 09:45:21

2020-09-06 22:59:35

Linux文件命令

2021-09-12 17:23:57

canvas动画函数

2020-09-24 11:46:03

Promise

2023-01-30 16:21:24

Linux外观

2009-09-02 17:51:36

.NET委托

2021-04-28 08:21:21

Promise.any服务器场景

2021-04-27 08:31:37

Promisereject信息

2021-08-04 17:55:38

keysRedis数据库

2019-05-30 10:15:30

2012-11-29 09:49:17

软件项目项目

2020-06-23 10:03:33

版本控制项目

2020-07-09 18:46:52

物联网IIoT技术

2020-10-10 06:21:15

爬虫互联网
点赞
收藏

51CTO技术栈公众号