等待在没有 setTimeout 的情况下定义值?

rpi*_*var 6 javascript async-await ecmascript-6 es6-promise

我正在从某个地方获取一个值并希望在本地使用它(使用 lodash):

const setting = _.get(this.settings, 'options');
Run Code Online (Sandbox Code Playgroud)

this.settings.options设置在其他地方,取决于环境,this.settings.options可能未定义。在这种情况下,我可以执行以下操作:

const set = (setting) => {
  ...
  ...
};

const getThing = () => {
  setTimeout(() => {
    const setting = _.get(this.settings, 'options');
    return setting ? set(setting) : getThing();
  }, 1000);
};

getThing();
Run Code Online (Sandbox Code Playgroud)

这使用一个setTimeout函数来等待 1 秒this.settings.options以在该时间内设置,如果尚未设置,则该setTimeout函数会在 1 秒后调用自身进行检查。之后,它继续set()使用获取的数据执行该功能。这似乎每次都有效,但如果我能一直检查这个值直到它在没有计时器的情况下被定义,那就太好了。我不确定这是否可能?

我一直在尝试实现 promise 或使用 async / await 来执行此操作,但是我看到的示例似乎也使用了setTimeouts,并且解决方案最终看起来更复杂。其中,我主要是在看这个答案。无论如何,我在使用 async/await 执行此操作时遇到了麻烦,因此必须继续进行故障排除。

有没有办法在不使用 asetTimeout或 的情况下等待定义此值setInterval

FZs*_*FZs 1

不幸的是,没有直接的方法可以做到这一点。

如果你可以变异this.settings(并且this.settings.options至少是可配置的),那么你可以定义一个setter,并等待它被触发。

这通常是一种丑陋的模式(只有在没有其他方法的情况下才使用它),但仍然比定期检查属性的存在要好。

请注意,.options只有当设置的神秘代码使用[[Set]](即,obj.prop = valueReflect.set)而不是[[Define]](即, )时,这才有效Object.defineProperty

if(typeof this.settings.options==='undefined'){
  //Define a setter
  Object.defineProperty(this.settings, 'options', {
    set: (value)=>{
      //Remove setter, and transform to simple property
      Object.defineProperty(this.settings, 'options', {value})
      //Hypothetical function to be called with the result
      doSomethingWithTheValue(value)
    },
    configurable: true,
    enumerable: true
  })
}else{
  doSomethingWithTheValue(this.settings.options)
}
Run Code Online (Sandbox Code Playgroud)

而且,您现在可以轻松地将其重写为使用 s 的通用函数Promise(因此支持async/ await):

function getAsync(obj, prop){
  return new Promise((resolve,reject)=>{
    if(typeof obj[prop]==='undefined'){
      Object.defineProperty(obj, prop, {
        set: (value)=>{
          Object.defineProperty(obj, prop, {value})
          resolve(value)
        },
        configurable: true,
        enumerable: true
      })
    }else{
      resolve(obj[prop])
    }
  })
}

getAsync(this.settings,'options')
  .then(doSomethingWithTheValue)

//or, async/await:

(async()=>{
  const value=await getAsync(this.settings,'options')
  doSomethingWithTheValue(value)
})
Run Code Online (Sandbox Code Playgroud)