那天我正在学习 Promise, 突然家里打电话过来说, 家里盖房子要钱. 我工作这么多年了, 从事着别人眼中高薪工作, 于是满口答应下来. 但是由于我并没有钱, 于是我跟家里说, 等过几天我再打钱过去. 我也好乘着这几天想想办法.
首先我找到我的同学李雷, 他现在一个部门经理了, 我想应该他应该有钱. 我跟他说明了借钱的意向, 李雷二话不说就答应借我 300, 不过同时表示要回家跟老婆商量商量, 我说好. 此时我想起来答应或者说承诺的英文单词就是 Promise . 承诺的结果是钱, 钱是数值(number 类型). 于是我想把我要借钱的这一行为写成一个 TypeScript 函数如下:
- // 向李雷借钱, 李雷丢给我一个承诺
- function borrowMoneyFromLiLei(): Promise {
- return new Promise(function(fulfill, reject) {
- // 李雷跟老婆商量中
- });
- }
此时, 我在想李雷老婆会答应给我借 300 块吗? 我不确定, 就像薛定谔的猫. 借还是不借, 这是一个问题. 然后我发现这也可以写成一个函数. 借或者不借用布尔值来表示 (boolean 类型). 函数如下:
- // 李雷的老婆是否会答应给我借钱?
- function willLiLeiWifeLendMeMoeny(): Promise {
- return new Promise(function(lend, reject) {
- // 借还是不借
- });
- }
如果李雷借我钱了, 我就转钱给家里, 没有, 我应该要再去找别人借了. 可以用下面的函数描述我此时的处境.
- function transferMoneyToHome(money: number) {
- // 给家里转钱
- }
- function mySituation(){
- borrowMoneyFromLiLei()
- .then((money:number) => {
- // 如果李雷借我钱了, 我就转钱给家里.
- transferMoneyToHome(money)
- }).catch((reason) => {
- // 李雷老婆拒绝借钱给我. 那我应该考虑向其他人借了.
- borrowMoneyFromOthers()
- })
- }
找其他人借, 我能想到就 (张三, 李四, 五五) 这三个人了, 其他的朋友很少联系, 突然说借钱也不好. 于是我尝试向他们借钱. 用代码表示是这样子的:
- function borrowMoneyFromOthers() {
- // 我先试着向张三借
- tryBorrowMoneyFromZhangshan()
- .then(money => {
- transferMoneyToHome(money);
- })
- .catch(reason => {
- // 如果张三不借, 并丢给我一个理由
- // 试着向李四借
- tryBorrowMoneyFromLisi()
- .then(money => {
- transferMoneyToHome(money);
- })
- .catch(reason2 => {
- // 如果 李四也不肯错
- // 再试试向王五借
- tryBorrowMoneyFromWangwu()
- .then(money => {
- transferMoneyToHome(money);
- })
- .catch(reason => {
- // 没有人肯借
- throw new Error("我该怎么办呢?");
- });
- });
- });
- }
由于借着钱之后都是向家里转钱, 所以上面的代码应该简化一下. 简化后如下:
- function borrowMoneyFromOthers() {
- // 我先试着向张三借
- tryBorrowMoneyFromZhangshan()
- .then(transferMoneyToHome)
- .catch(reason => {
- // 如果张三不借, 并丢给我一个理由
- // 试着向李四借
- tryBorrowMoneyFromLisi()
- .then(transferMoneyToHome)
- .catch(reason2 => {
- // 如果 李四也不肯错
- // 再试试向王五借
- tryBorrowMoneyFromWangwu()
- .then(transferMoneyToHome)
- .catch(reason => {
- // 没有人肯借
- throw new Error("我该怎么办呢?");
- });
- });
- });
- }
在上面的思路中, 我是一个一个找他们借钱的, 一个借不着再找另一个. 我为什么不同时找他们借呢? 谁借我了, 我就转钱给家里. 此时我想起了刚学的 Promise.race 方法, 也许这个方法可以帮助我表达我的这一决策需求.
- function borrowMoneyFromOthers() {
- // 同时向张三, 李四, 王五借钱, 只要有人借我钱了, 我就转钱给家里.
- Promise.race([
- tryBorrowMoneyFromZhangshan(),
- tryBorrowMoneyFromLisi(),
- tryBorrowMoneyFromWangwu()
- ])
- .then(transferMoneyToHome)
- .catch(reasons => {
- console.warn("没一个人愿意给我借钱, 他们理由是:", reasons);
- });
- }
我用 timeout 模拟一下他们给我答复的, 代码如下:
- // 尝试找张三借
- function tryBorrowMoneyFromZhangshan(): Promise {
- return new Promise(function(fulfill, reject) {
- setTimeout(() => {
- fulfill(300);
- }, 100);
- });
- }
- // 尝试找李四借
- function tryBorrowMoneyFromLisi(): Promise {
- return new Promise(function(fulfill, reject) {
- setTimeout(() => {
- reject("对不起我也没钱");
- }, 50);
- });
- }
- // 尝试找王五借
- function tryBorrowMoneyFromWangwu(): Promise {
- return new Promise(function(fulfill, reject) {
- setTimeout(() => {
- fulfill(300);
- }, 500);
- });
- }
结果运行之后, 控制台输出的是:
没一个人愿意给我借钱, 他们理由是: 对不起我也没钱
看来 Promise.race 适用用来模拟抢答, 而不是选择最优解. 比如多人抢答一个问题, 第一个抢答之后不论他回答的是否是正确, 这个题都过了.
不过没关系. 也许我可以自己写一个来叫做 promiseOne 的函数来实现这个功能. 代码如下:
- /**
- * 当其中一个 Promise 兑现时, 返回的 Promise 即被兑现
- * @param promises Promise 的数组
- */
- function promiseOne(promises: Promise[]): Promise {
- const promiseCount = promises.length;
- return new Promise(function(resolve, reject) {
- const reasons: any[] = [];
- let rejectedCount = 0;
- promises.forEach((promise, index) => {
- promise.then(resolve).catch(reason => {
- reasons[index] = reason;
- rejectedCount++;
- if (rejectedCount === promiseCount) {
- reject(reasons);
- }
- });
- });
- });
- }
正当我写完了上面的代码, 他们三个给我回话了, 说是现在手上也没有那么多钱, 但是可以给我借 100. 于是我现在需要处理这样的事情, 就是当他们三个人把钱都转给我之后我再转给家里. 当他们三个都兑换借我 100 块钱的承诺时, 可以用 Promise.all 来表示, 代码如下:
- function borrowMoneyFromOthers() {
- // 同时向张三, 李四, 王五借钱, 借到之后, 我就转钱给家里.
- Promise.all([
- tryBorrowMoneyFromZhangshan(),
- tryBorrowMoneyFromLisi(),
- tryBorrowMoneyFromWangwu()
- ])
- .then(moneyArray => {
- console.info("借到钱啦:", moneyArray);
- const totalMoney = moneyArray.reduce((acc, cur) => acc + cur);
- transferMoneyToHome(totalMoney);
- })
- .catch(reasons => {
- console.warn("有人不愿意给我借钱, 理由是:", reasons);
- });
- }
现在有三个人愿意给我借钱了, 嗯, 也就是说我借到了 300 块. 然而这钱用来建房还是杯水车薪. 所以我还得想办法. 我想我要不要试试用这 300 块来买一下彩票. 如果中了, 说不定这事就成了.
- function buyLottery(bet: number): Promise {
- return new Promise(function(fulfill, resolve) {
- // 投注
- // 等待开奖
- setTimeout(() => {
- resolve("很遗憾你没有买中");
- }, 100);
- });
- }
- function borrowMoneyFromOthers() {
- // 同时向张三, 李四, 王五借钱,
- Promise.all([
- tryBorrowMoneyFromZhangshan(),
- tryBorrowMoneyFromLisi(),
- tryBorrowMoneyFromWangwu()
- ])
- .then(moneyArray => {
- console.info("借到钱啦:", moneyArray);
- const totalMoney = moneyArray.reduce((acc, cur) => acc + cur);
- // 购买彩票
- buyLottery(totalMoney)
- .then(transferMoneyToHome)
- .catch(reason => {
- console.log("没中,", reason);
- });
- })
- .catch(reasons => {
- console.warn("有人不愿意给我借钱, 理由是:", reasons);
- });
- }
我知道很大概率我是买不中的, 最近世界杯开赛了, 我幻想着压注世界杯, 而且世界杯场次多, 一天好几场, 一场买中的盈利还可以投入到下一场. 我把我的幻想写成代码, 大概就是下面这样.
- function betWorldCup() {
- // 初始资金 300 块
- Promise.resolve(300)
- .then(moeny => {
- // 投西班牙
- return new Promise(function(fulfil, reject) {
- setTimeout(() => {
- // 假假设 赔率 1.2
- fulfil(moeny * 1.2);
- }, 100);
- });
- })
- .then(ret => {
- // 投英格兰
- return ret * 1.2;
- })
- .then(ret => {
- // 投巴西
- return new Promise(function(fulfil, reject) {
- setTimeout(() => {
- fulfil(ret * 1.2);
- }, 92);
- });
- })
- .then(ret => {
- console.log("现在收益加本金共有:", ret);
- });
- }
我想, 如果第一场投失败了, 应该再给自己一次机会. 于是将代码修改如下:
- function betWorldCup() {
- // 初始资金 300 块
- Promise.resolve(300)
- .then(moeny => {
- // 投西班牙
- return new Promise(function(fulfil, reject) {
- setTimeout(() => {
- // 假假设 赔率 1.2
- // fulfil(moeny * 1.2);
- reject("庄家跑跑路了");
- }, 100);
- });
- })
- .then(
- ret => {
- // 投英格兰
- return ret * 1.2;
- },
- reason => {
- console.info("第一次投注失败, 再给一次机会好不好?, 失败原因:", reason);
- // 再投 300
- return 300;
- }
- )
- .then(ret => {
- // 投巴西
- return new Promise(function(fulfil, reject) {
- setTimeout(() => {
- fulfil(ret * 1.2);
- }, 92);
- });
- })
- .then(ret => {
- console.log("现在收益加本金共有:", ret);
- throw new Error("不要再买了");
- })
- .then(ret => {
- console.info("准备再买吗?");
- })
- .catch(reason => {
- console.log("出错了:", reason);
- });
- }
此时如下运行上面的函数会得到如下输出:
第一次投注失败, 再给一次机会好不好?, 失败原因: 庄家跑跑路了
现在收益加本金共有: 360
出错了:
Error: 不要再买了
然而, 幻想结束之后, 我依然得苦苦思考怎么样筹钱.
来源: http://developer.51cto.com/art/201807/577713.htm