代码之家  ›  专栏  ›  技术社区  ›  Rasim Avcı

如何履行承诺。解析需要原子化的代码

  •  1
  • Rasim Avcı  · 技术社区  · 7 年前

    我正在开发一个合作伙伴管理器,一些代码需要原子化,因为当前存在竞争条件,当两个客户端同时调用同一资源时无法工作。retrievePartners方法返回partners,该方法应该是原子的。Basicaly partners是有限的资源,提供机制一次只能处理一个客户(请求合作伙伴)。

    我被告知下面的代码适用于原子操作,因为javascript在本机上是原子的。

    let processingQueue = Promise.resolve();
    
    function doStuffExclusively() {
    
      processingQueue = processingQueue.then(() => {
          return fetch('http://localhost', {method: 'PUT', body: ...});
      }).catch(function(e){
          throw e;
      });
    
      return processingQueue;
    }
    
    doStuffExclusively()
    doStuffExclusively()
    doStuffExclusively()
    

    然而,这段代码是基本的,我的代码有一些await调用另一个await,以此类推。我想为下面的代码应用这种机制,但真的不知道怎么做,我尝试了一些技巧,但没有成功。无法在then语句中获取等待工作。

    我还感到困惑的是,上面的代码在processingQueue的那个部分返回true。然而,在我的例子中,我返回一个数组,或抛出一条错误消息。我应该退回一些东西让它像上面那样工作吗。

    这是我想让原子化的函数,就像上面的代码一样。我试图将此函数中的所有内容都放在返回语句之前的then部分中,但没有成功,因为

    export class Workout {
      constructor (config) {
        this.instructorPeer = new jet.Peer(config)
        this.instructorPeer.connect()
      }
    
      async createSession (partnerInfo) {
        const partners = { chrome: [], firefox: [], safari: [], ie: [] }
        const appropriatePartners = await this.retrievePartners(partnerInfo)
        Object.keys(appropriatePartners).forEach(key => {
          appropriatePartners[key].forEach(partner => {
            const newPartner = new Partner(this.instructorPeer, partner.id)
            partners[key].push(newPartner)
          })
        })
    
        return new Session(partners)
      }
      async retrievePartners (capabilities) {
        const appropriatePartners = { chrome: [], firefox: [], safari: [], ie: [] }
        const partners = await this.getAllPartners()
    
        // first check if there is available appropriate Partners
        Object.keys(capabilities.type).forEach(key => {
          let typeNumber = parseInt(capabilities.type[key])
          for (let i = 0; i < typeNumber; i++) {
            partners.forEach((partner, i) => {
              if (
                key === partner.value.type &&
                partner.value.isAvailable &&
                appropriatePartners[key].length < typeNumber
              ) {
                appropriatePartners[key].push(partner)
                console.log(appropriatePartners[key].length)
              }
            })
    
            if (appropriatePartners[key].length < typeNumber) {
              throw new Error(
                'Sorry there are no appropriate Partners for this session'
              )
            }
          }
        })
    
        Object.keys(appropriatePartners).forEach(key => {
          appropriatePartners[key].forEach(partner => {
            this.instructorPeer.set('/partners/' + partner.id + '/states/', {
              isAvailable: false
            })
          })
        })
    
        return appropriatePartners
      }
    
      async getAllPartners (capabilities) {
        const partners = []
        const paths = await this.instructorPeer.get({
          path: { startsWith: '/partners/' }
        })
        paths.forEach((path, i) => {
          if (path.fetchOnly) {
            let obj = {}
            obj.value = path.value
            obj.id = path.path.split('/partners/')[1]
            obj.value.isAvailable = paths[i + 1].value.isAvailable
            partners.push(obj)
          }
        })
        return partners
      }
    

    下面是调用它的代码

    async function startTest () {
      const capabilities = {
        type: {
          chrome: 1
        }
      }
      const workoutServerConfig = {
        url: 'ws://localhost:8090'
      }
      const workout = createWorkout(workoutServerConfig)
      const session = await workout.createSession(capabilities)
      const session1 = await workout.createSession(capabilities)
    

    这是我尝试的,但没有奏效,会话没有定义等等

    let processingQueue = Promise.resolve()
    
        export class Workout {
      constructor (config) {
        this.instructorPeer = new jet.Peer(config)
        this.instructorPeer.connect()
    this.processingQueue = Promise.resolve()
      }
    
      async createSession (partnerInfo) {
        this.processingQueue = this.processingQueue.then(() => {
          const partners = { chrome: [], firefox: [], safari: [], ie: [] }
          const appropriatePartners = this.retrievePartners(partnerInfo)
          Object.keys(appropriatePartners).forEach(key => {
            appropriatePartners[key].forEach(partner => {
              const newPartner = new Partner(this.instructorPeer, partner.id)
              partners[key].push(newPartner)
            })
          })
    
          return new Session(partners)
        })
      }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   jagthebeetle    7 年前

    这是基于承诺的锁定,基于以下事实:

    1) the .then() 只有在解决了锁之后,才会调用处理程序。

    2) 一旦 .然后() 处理程序开始执行,由于JS的执行模型,不会执行其他JS代码。

    您引用的方法的总体结构是正确的。

    我看到的代码的主要问题是 const appropriatePartners = this.retrievePartners(partnerInfo) 将评估为承诺,因为 retrievePartners 是异步的。您想:

    const appropriatePartners = await this.retrievePartners(partnerInfo)

    这将导致锁的执行器阻止 检索合作伙伴 调用,而当前您只是获取一个封装该调用最终返回值的承诺。

    编辑:请参见 jsfiddle 例如。

    总计:

    1) 使箭头功能处理锁定分辨率 async

    2) 确保它 await s的返回值 this.retrievePartners ,否则您将按承诺操作,而不是按解析值操作。