使用Promise隊列在業務層面分配資源

背景

最近在寫一個steam和一些交易平臺的自動交易的機器人,涉及到一個很簡單的業務邏輯:買賣操做都須要登陸權限,若在進行操做時登陸失效則須要先去登陸再繼續該邏輯並返回結果。要解決的問題以下:併發

  1. 同時多個操做都須要登陸時怎麼只讓機器人登陸一次而後通知這些操做?
  2. 如何在登陸後繼續操做(相似斷點的概念)?

代碼實現

在初期寫下簡單的代碼以下:this

class Robot {
  constructor() {
    this.loginStatus = 'LOG_OUT'
  }

  login() {
    return new Promise((gRes, gRej) => {
      // 模擬登陸
      setTimeout(gRes, 10000)
    })
  }

  buy() {
    if (this.loginStatus === 'LOG_OUT') {
      // 等待登陸後繼續操做
      this.login()
        .then(() => {
          // 繼續操做
         })
    } else {
      // 正常業務流程
    }
  }

  sell() {
    if (this.loginStatus === 'LOG_OUT') {
      // 等待登陸後繼續操做
        this.login()
          .then(() => {
            // 繼續操做
           })
    } else {
      // 正常業務流程
    }
  }
}

在第一次毫無思考的狀況下寫下這個代碼,看似沒有問題,可是因爲 loginStatus 是個公共資源其實應該是須要在被搶佔後阻止其餘操做順利讀取或修改該變量。該機器人會有大量的併發地調用 buysell 方法,若是有一時刻登陸失效了,那就會致使事實上的login屢次進行登陸操做(代碼中用setTimeout來模擬其實是發請求登陸),形成資源浪費,且每次返回的token不一致致使業務邏輯混亂。code

本身想的解決辦法其實也不好勁,分享出來以下:token

class Robot {
  constructor() {
    this.isInLogin = false
    this.loginStatus = 'LOG_OUT'
    this.loginDep = []
  }

  login() {
    return new Promise((gRes, gRej) => {
      this.loginDep.push({resolve: gRes, reject: gRej})
      if (this.isInLogin) {
        return
      }
      this.isInLogin = true
      // 模擬登陸
      setTimeout(() => {
        // 登陸完成
        this.loginDep.forEach(({ resolve, reject }) => {
          resolve()
        })
        this.isInLogin = false
      }, 10000)
    })
  }

  buy() {
    if (this.loginStatus === 'LOG_OUT') {
      // 等待登陸後繼續操做
      this.login()
        .then(() => this.buy())
    } else {
      // 正常業務流程
    }
  }

  sell() {
    if (this.loginStatus === 'LOG_OUT') {
      // 等待登陸後繼續操做
      this.login()
        .then(() => this.sell())
    } else {
      // 正常業務流程
    }
  }
}

以上是初版改版後的寫法,在代碼中運行良好,次日又想到Promise的意思就是承諾,既然login是一個操做那login就是一個承諾。改版後以下:資源

class Robot {
  constructor() {
    this.loginStatus = 'LOG_OUT'
    this.loginPromise = null
  }

  login() {
    if (this.loginPromise) {
      return this.loginPromise
    }
    let loginPromise = new Promise((gRes, gRej) => {
      // 模擬登陸
      setTimeout(() => {
        // 登陸完成
        this.loginPromise = null
      }, 10000)
    })
    return loginPromise
  }

  buy() {
    if (this.loginStatus === 'LOG_OUT') {
      // 等待登陸後繼續操做
       this.login()
        .then(() => this.sell())
    } else {
      // 正常業務流程
    }
  }

  sell() {
    if (this.loginStatus === 'LOG_OUT') {
      // 等待登陸後繼續操做
      this.login()
        .then(() => this.sell())
    } else {
      // 正常業務流程
    }
  }
}

以上是感受本身學到的地方,由於Promise你們都會用,怎麼用來解決實際業務場景仍是須要看我的的想法。若是你們有更好的實現方式請不吝賜教。class

2020年你們恭喜發財呀!登錄

相關文章
相關標籤/搜索