【问题标题】:Resolve promise on array push - javascript解决数组推送的承诺 - javascript
【发布时间】:2020-01-20 10:49:06
【问题描述】:

我正在尝试定义一个返回承诺的函数。当设置给定数组时,promise 应该会解析 (push())。

为此,我尝试使用代理对象(受this 影响):

let a = []

;(async function(){

  const observe = array => new Promise(resolve =>
      new Proxy(array, {
          set(array, key, val) {
              array[key] = val;
              resolve();
            }
      }));

  while(true){

      await observe(a);
      console.log(new Date().toLocaleTimeString(),"Blimey Guv'nor:",`${a.pop()}`);
    }

})(a);

;(async function(){
    await new Promise(resolve => timerID = setTimeout(resolve, 2000))
    a.push('ʕ·͡ᴥ·ʔ');
    a.push('¯\(°_o)/¯ ')
})(a)

我不明白为什么这不起作用。有人知道吗?

更一般地说,什么是在推送到数组时解决 promise 的好方法?

【问题讨论】:

标签: javascript asynchronous promise async-await


【解决方案1】:

你尝试的问题:

  • 您在原始数组上调用.push,而不是代理数组。在您创建代理的地方,它不会返回给任何人:对它的任何引用都会丢失(并将被垃圾收集)。
  • await 之后的代码将异步执行,所以毕竟你的push 调用已经执行。这意味着console.log 将在数组已经有两个元素时执行。因此,Promise 不是您想要的正确工具,因为只有在所有其他同步代码运行完成时才能执行 Promise 的解析。要执行期间同步获取通知,您需要一个同步解决方案,而promise是基于异步执行的。

为了补全答案,我这里提供一个简单的同步回调解决方案:

function observed(array, cb) {
    return new Proxy(array, {
        set(array, key, val) {
            array[key] = val;
            if (!isNaN(key)) cb(); // now it is synchronous
            return true;
        }
    });
}

let a = observed([], () =>
    console.log(new Date().toLocaleTimeString(),"Blimey Guv'nor:", `${a.pop()}`)
);

a.push('ʕ·͡ᴥ·ʔ');
a.push('¯\(°_o)/¯ ');

如前所述:当您需要同步代码执行时,promise 不是正确的工具。

当每个push异步执行时

可以使用 Promise,如果您确定每个 push 发生在一个单独的任务中,其中 Promise 作业队列在每对 push 调用之间进行处理。

例如,如果您将每个 push 调用作为输入事件处理程序的一部分,或者作为 setTimeout 计时器的回调,那么它是可能的:

function observed(array) {
    let resolve = () => null; // dummy
    let proxy = new Proxy(array, {
        set(array, key, val) {
            array[key] = val;
            if (!isNaN(key)) resolve();
            return true;
        }
    });
    proxy.observe = () => new Promise(r => resolve = r);
    return proxy;
}


let a = observed([]);
(async () => {
    while (true) {
        await a.observe();
        console.log(new Date().toLocaleTimeString(),"Blimey Guv'nor:",`${a.pop()}`);
    }
})();

setTimeout(() => a.push('ʕ·͡ᴥ·ʔ'), 100);
setTimeout(() => a.push('¯\(°_o)/¯ '), 100);

【讨论】:

  • 好点。第一个确实帮助我理解了我的错误。关于。第二个 - 我不清楚这个问题(数组推送应该是通过控制台,或者在延迟之后)。我会调整问题,谢谢。
  • 编辑后,两个push 调用仍然在同一段同步代码中执行(即使该段本身是异步执行的)。在这两个push 调用之间不可能有一个承诺解决方案。他们确实需要各自在一个单独的异步作业中,以便承诺有机会在两者之间触发作业。
  • 查看补充答案。
  • 太棒了!在我的用例中,许多推送调用确实是异步的(同样应该更清楚)。谢谢。
猜你喜欢
  • 1970-01-01
  • 2017-02-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多