有没有办法递归等待 Javascript 中的值?

Is there a way to recursively await a value in Javascript?

我正在用 Javascript 制作一个项目,并且我有一个对象具有 returns 承诺的 getter。我可以用这段代码模拟这个对象:

async function asyncifiedObject(object) {
  let o = {};

  let keys = [...Object.keys(object)];
  for (let item of keys) {
    o.__defineGetter__(item, async () => {
      if (object && object[item]) {
        if (typeof object[item] == "object") {
          // Do other async things, like network requests, etc.
          return await asyncifiedObject(object[item]);
        } else {
          return object[item];
        }
      }
    });
  }
  return o;
}

我得到了这样的对象之一:

let o=asyncifiedObject({hello:{world:{it:{is:{nice:{out:"today"}}}}}})

当我去访问对象的属性时,我目前正在做 await (await (await (await (await (await (await o).hello).world).it).is).nice).out,但是那很长而且看起来很糟糕。

我可以像 await getAsyncValues(o,"hello","world","it","is","nice","out") 那样使用一个函数来完成它,但我想做的是 await o.hello.world.it.is.nice.out 之类的事情,但这行不通,因为所有的承诺都需要等待,不仅仅是第一个。有什么可行的方法吗?

顺便说一下,这里是 getAsyncValues 的示例实现:

async function getAsyncValues(object,...values){
  let r=object;
  for(let value of values){
    r=(await r)[value]
  }
  return r
}

这是一个有趣的情况。不,这里没有任何语法可以帮助您,您需要使用您的函数或类似函数。

我想出了一个方法让这个工作完全按照我想要的方式进行! await 语句不仅仅适用于 promises。它也适用于 thenables。 thenable 是一个具有类似于 Promise 的 then 方法的对象。我修改了getAsyncValues,最终代码如下

(async () => {
  async function asyncifiedObject(object) {
    let o = {};

    let keys = [...Object.keys(object)];
    for (let item of keys) {
      o.__defineGetter__(item, async () => {
        if (object && object[item]) {
          if (typeof object[item] == "object") {
            // Do other async things, like network requests, etc.
            return thenableHack(await asyncifiedObject(object[item]));
          } else {
            return object[item];
          }
        }
      });
    }
    return o;
  }

  function thenableHack(object, ...values) {
    let o = {
      then: async e => {
        let r = object;
        for (let value of values) {
          r = (await r)[value];
        }
        e(r);
      },
      catch: () => {}
    };
    return new Proxy(o, {
      get: (o, p) => {
        return o[p] || thenableHack(object, ...values, p);
      }
    });
  }

  let o = thenableHack(
    asyncifiedObject({
      hello: { world: { it: { is: { nice: { out: "today" } } } } }
    })
  );
  console.log(await o.hello.world.it.is.nice.out);
})();