如何将Promise.resolve应用于需要原子的代码

时间:2018-04-17 08:41:29

标签: javascript promise atomic

我正在研究合作伙伴经理,有些代码需要是原子的,因为当2个客户同时调用相同的资源时,目前存在竞争条件并且无法工作。 retrievePartners方法返回合作伙伴,该方法应该是原子的。 Basicaly合作伙伴是有限的资源,提供机制应该一次只处理一个客户(请求合作伙伴)。

我被告知下面的代码适用于原子操作,因为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()

然而,这段代码是基本的,我的代码有一些等待调用另一个等待,等等。我想将这种机制应用于下面的代码,但实际上不知道该怎么做,我尝试了很少但没有工作。无法在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 个答案:

答案 0 :(得分:1)

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

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

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

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

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

const appropriatePartners = await this.retrievePartners(partnerInfo)

这会导致你的锁的执行者在retrievePartners调用时阻塞,而目前你只是抓住一个包含该调用最终返回值的声明。

修改:有关示例,请参阅jsfiddle

总之:

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

2)确保awaitthis.retrievePartners的返回值,否则您将对Promise进行操作,而不是已解析的值。