【问题标题】:Wait for value to be defined without setTimeout?等待在没有 setTimeout 的情况下定义值?
【发布时间】:2020-01-12 16:49:22
【问题描述】:

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

const setting = _.get(this.settings, 'options');

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();

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

我一直在尝试实现 promise 或使用 async / await 来执行此操作,但我看到的示例似乎也使用了setTimeouts,而最终解决方案似乎更加复杂。其中,我主要关注this answer。无论如何,我在使用 async / await 时遇到了问题,并且必须继续排除故障。

有没有办法在不使用setTimeoutsetInterval 的情况下等待这个值被定义?

【问题讨论】:

  • 您可以使用set 方法来处理设置的设置,并在该方法中调用一个回调函数,它会告诉您该设置刚刚设置。您甚至可以使用事件侦听器来执行此操作,然后它将类似于 addEventListener('setting-was-set', setting => /* 在此处使用设置 */) developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… developer.mozilla.org/en-US/docs/Web/API/EventListener
  • 是的,几乎总有比使用超时轮询来显示值更好的方法。但是,请告诉我们更多关于“this.settings.options 设置在其他位置,根据环境,它可能是undefined.”。 “其他地方”到底在哪里,它仍然在同一个代码单元中,什么时候发生设置?或者环境什么时候决定选择保留undefined
  • 有时此代码在本地环境中运行,有时它与接收器单元一起工作。当涉及接收器单元时,可能存在延迟。在这种特殊情况下,我可以查询此数据的唯一位置是 this.settings.options 中的任何内容,因此除了等待设置该属性之外没有其他解决方法(不确定这是否是您要查找的内容)跨度>
  • @rpivovar 但您的代码预先知道是否有接收器单元?它可以调用该接收器单元的方法吗?也许你可以发布接收单元的代码。
  • 这是一个XY Problem,原因是对 Promise 和一般异步的误解。请粘贴您的真实程序并解释它试图解决的问题。显示示例输入和输出。见相关:How do I return the response from an asynchronous call?

标签: javascript ecmascript-6 async-await es6-promise


【解决方案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)
}

而且,您现在可以轻松地将其重写为使用Promises 的通用函数(因此支持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)
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-24
    • 2013-07-22
    • 2020-05-11
    • 1970-01-01
    • 2021-11-12
    • 2013-05-18
    相关资源
    最近更新 更多