承诺设计模式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了承诺设计模式相关的知识,希望对你有一定的参考价值。

我已经创建了一个SoundManager来处理我的应用程序中的声音。在我的应用程序中,我实例化一个SoundManager,然后使用它来加载音频文件,并在加载后返回一个承诺。

我省略了一些代码,因为我认为在这种情况下不重要 - 我知道它们都正确加载,例如,我的应用程序中的then()函数,它从loadSounds()传递的Promises数组接收一个对象所有的声音(不是承诺)。

但是,如果从我的应用程序(在声音全部加载的位置),我调用playSound()this.sounds变量将是一个Promises数组。

为什么会这样?一旦承诺得以实现,this.sounds中的变量SoundManager不应更新吗?

这也不是一个好的模式,所以有关如何实现这一点的任何想法?

import Promise from 'bluebird';
import {Howl, Howler} from 'howler';

export default class SoundManager {
  constructor(){
    this.sounds;
  }

  loadSounds(soundsArray){
    this.sounds = soundsArray.map((data) => {
      return new Promise((resolve, reject) => {        
        // ...
      })
    })
    return Promise.all(this.sounds)
  }

  playSound(id){
    console.log('this.sounds: ', this.sounds); //this is an array of promises, when I expect an array of sound objects
    let sound = this.sounds.filter((sound) => sound.id === id);
    if (!sound.length) {
      console.warn(`could not find sound with id "${id}"`)
      return false;
    }
    sound[0].play()
  }
}
答案

this.sounds包含一系列承诺,因为这正是你在这里指定的:

  loadSounds(soundsArray){
    this.sounds = soundsArray.map((data) => {
      return new Promise((resolve, reject) => {        
        // ...
      })
    })
    return Promise.all(this.sounds)
  }

你的soundsArray.map()的结果是一系列的承诺。

如果您希望它包含最终值,您可以这样做:

  loadSounds(soundsArray){
    let sounds = soundsArray.map((data) => {
      return new Promise((resolve, reject) => {        
        // ...
      })
    })
    return Promise.all(sounds).then(data => {
        this.sounds = data;
        return data;
    });
  }

虽然这样做似乎有点问题,因为除了使用loadSounds()返回的承诺之外,没有其他方法可以知道this.sounds何时包含您想要的数据。因此,如果知道数据何时存在的唯一方法是loadSounds()返回的承诺,则不清楚其他代码如何能够可靠地使用this.sounds

您可以在Promise.all()中存储来自this.sounds的承诺,然后任何想要声音的代码都可以使用this.sounds.then()来获取它。我们必须看到更多你正在尝试用this.sounds做什么,当你想要做的时候才知道最好的设计是什么。

另一答案

一旦履行承诺,SoundManager中的变量this.sounds不应该更新吗?

不,这不是承诺的工作方式。他们保留承诺对象,他们不会“成为”他们所实现的价值。

这看起来不是一个好模式

是的,不要在管理器中加载声音。经理可能会或可能不会在其生命周期内使用 - 这不是特别有用。只有在加载声音后才能更好地实例化 - 请参阅this also here

export default class SoundManager {
  constructor(sounds) {
    this.sounds = sounds;
  }

  static loadAndCreate(soundsArray) {
    return Promise.all(soundsArray.map((data) => {
      return new Promise((resolve, reject) => {        
        …
      })
    })).then(sounds => new this(sounds));
  }

  playSound(id){
    console.log('this.sounds: ', this.sounds); //this is always an array of sound objects
    let sound = this.sounds.find(sound => sound.id === id);
    if (!sound) {
      console.warn(`could not find sound with id "${id}"`)
      return false;
    }
    sound.play()
  }
}

以上是关于承诺设计模式的主要内容,如果未能解决你的问题,请参考以下文章

在另一个被认为是反模式的承诺中使用承诺?

用于从 cloudkit 检索单列的代码模式/片段

如果一个已经在运行的 PromiseKit 承诺返回一个未决的承诺的最佳 Swift 模式是啥?

是否有在单个活动中处理多个片段的 Android 设计模式?

打字稿中的Angular js Http承诺

蓝鸟承诺 - 嵌套与拒绝模式