用 Promise 描述一個悲傷的故事

那天我正在學習 Promise,忽然家裏打電話過來講,家裏蓋房子要錢。我工做這麼多年了,從事着別人眼中高薪工做,因而滿口答應下來。可是因爲我並無錢,因而我跟家裏說,等過幾天我再打錢過去。我也好乘着這幾天想一想辦法。數組

首先我找到個人同窗李雷,他如今一個部門經理了,我想應該他應該有錢。我跟他說明了借錢的意向,李雷二話不說就答應借我300,不過同時表示要回家跟老婆商量商量,我說好。此時我想起來答應或者說承諾的英文單詞就是 Promise。承諾的結果是錢,錢是數值(number 類型)。因而我想把我要借錢的這一行爲寫成一個TypeScript 函數以下:promise

// 向李雷借錢,李雷丟給我一個承諾
function borrowMoneyFromLiLei(): Promise<number> {
  return new Promise<number>(function(fulfill, reject) {
     // 李雷跟老婆商量中
  });
}

複製代碼

此時,我在想李雷老婆會答應給我借300塊嗎?我不肯定,就像薛定諤的貓。借仍是不借,這是一個問題。而後我發現這也能夠寫成一個函數。借或者不借用布爾值來表示 (boolean 類型)。函數以下:bash

// 李雷的老婆是否會答應給我借錢?
function willLiLeiWifeLendMeMoeny(): Promise<boolean> {
  return new Promise<boolean>(function(lend, reject) {
    // 借仍是不借
  });
}
複製代碼

若是李雷借我錢了,我就轉錢給家裏,沒有,我應該要再去找別人借了。能夠用下面的函數描述我此時的處境。markdown

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 方法,也許這個方法能夠幫助我表達個人這一決策需求.spa

function borrowMoneyFromOthers() {
  // 同時向張三,李四,王五借錢,只要有人借我錢了,我就轉錢給家裏。
  Promise.race([
    tryBorrowMoneyFromZhangshan(),
    tryBorrowMoneyFromLisi(),
    tryBorrowMoneyFromWangwu()
  ])
    .then(transferMoneyToHome)
    .catch(reasons => {
      console.warn("沒一我的願意給我借錢,他們理由是:", reasons);
    });
}

複製代碼

我用timeout 模擬一下他們給我答覆的,代碼以下:code

// 嘗試找張三借
function tryBorrowMoneyFromZhangshan(): Promise<number> {
  return new Promise(function(fulfill, reject) {
    setTimeout(() => {
      fulfill(300);
    }, 100);
  });
}
// 嘗試找李四借
function tryBorrowMoneyFromLisi(): Promise<number> {
  return new Promise(function(fulfill, reject) {
    setTimeout(() => {
      reject("對不起我也沒錢");
    }, 50);
  });
}
// 嘗試找王五借
function tryBorrowMoneyFromWangwu(): Promise<number> {
  return new Promise(function(fulfill, reject) {
    setTimeout(() => {
      fulfill(300);
    }, 500);
  });
}
複製代碼

結果運行以後,控制檯輸出的是:orm

沒一我的願意給我借錢,他們理由是: 對不起我也沒錢ip

看來 Promise.race 適用用來模擬搶答,而不是選擇最優解。 好比多人搶答一個問題,第一個搶答以後不論他回答的是不是正確,這個題都過了。

不過不要緊。也許我能夠本身寫一個來叫作 promiseOne 的函數來實現這個功能。代碼以下:

/** * 當其中一個 Promise 兌現時,返回的 Promise 即被兌現 * @param promises Promise<T> 的數組 */
function promiseOne<T>(promises: Promise<T>[]): Promise<T> {
  const promiseCount = promises.length;
  return new Promise<T>(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<number> {
  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<number>(function(fulfil, reject) {
        setTimeout(() => {
          // 假假設 賠率 1.2
          fulfil(moeny * 1.2);
        }, 100);
      });
    })
    .then(ret => {
      // 投英格蘭
      return ret * 1.2;
    })
    .then(ret => {
      // 投巴西
      return new Promise<number>(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<number>(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<number>(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: 不要再買了
複製代碼

然而,幻想結束以後,我依然得苦苦思考怎麼樣籌錢。

相關文章
相關標籤/搜索