【问题标题】:Wait until all promises are resolved in JavaScript等到所有的承诺都在 JavaScript 中解决
【发布时间】:2015-10-19 09:44:46
【问题描述】:

我不乐观有办法做到这一点,但我想把问题放在那里。情况:我正在编写一个为新手程序员量身定制的 JavaScript 游戏引擎。我希望主脚本界面尽可能简单且易于访问。理想情况下,脚本最终看起来像这样:

this.backdrop('backdrop-1.png', { effect: 'fade-in', duration: 1000, sync: true });
this.backdrop('backdrop-2.png', { effect: 'fade-in', duration: 500 });

在这种情况下,第一个背景会在一秒钟内完全淡入,然后第二个背景会同步淡入。问题? JavaScript 会在第一个命令完成之前尝试执行第二个命令。

现在,处理这个问题的正确方法是使用 Promise。比如:

this.backdrop('backdrop-1.png', { effect: 'fade-in', duration: 1000 }).then(() => {
  this.backdrop('backdrop-2.png', { effect: 'fade-in', duration: 500 });
});

这完全是一种选择。 (事实上​​,这可能是我必须接受的。)但我不想走这条路有两个原因。首先,它为本来应该是一个简单脚本的内容添加了许多额外的措辞。我希望这对新程序员来说看起来不那么吓人,所有这些嵌套函数都会开始看起来很可怕。其次,promise 不能很好地处理控制流。即使是像 if-then 语句这样简单的事情也会变得粗糙。

我真正想要的是某种方式来做到这一点:

this.backdrop('backdrop-1.png', { effect: 'fade-in', duration: 1000, sync: true });
waitUntilAllPromisesAreResolved();
this.backdrop('backdrop-2.png', { effect: 'fade-in', duration: 500 });

但那是白日梦,不是吗?如果你能想出一种方法来实现它,我很乐意听到。

【问题讨论】:

  • 或许你可以使用HTML5工作线程stackoverflow.com/questions/30036/javascript-and-threads/…来处理这种情况
  • 哦,这很有趣。我完全忘记了工人!我会进一步研究。
  • @HashPsi 那么你是否在想这样的事情:在工作人员上运行this.backdrop,然后在while循环中冻结主脚本直到this.backdrop解决?我以前没有尝试过这样的事情,而且我有点担心让主线程进入睡眠状态。不过,这可能是这里的最佳选择。
  • 再想一想,它可能不起作用,因为工作人员很可能无法修改 DOM(因为 DOM 访问不是线程安全的)。
  • 您可以让backdrop 的异步版本在每个块运行setTimeout 时分块执行它。 waitUntilAllPromisesAreResolved 将侦听backdrop 生成的事件,并仅在backdrop 完成时返回。不过,保持 UI 响应可能有些棘手。

标签: javascript promise


【解决方案1】:

它为本来应该是一个简单脚本的内容添加了很多额外的措辞。我希望这对新程序员来说看起来没有威胁性,所有这些嵌套函数都会开始看起来很可怕。

嗯,这比通过魔法完成的脚本要好得多(这当然可能,见下文)。大多数新手将能够弄清楚then 做了什么,但他们无法识别魔法 - 当某些东西不起作用时会完全糊涂。

顺便说一句,在回调上使用 Promise 时,您几乎应该 never have to nest functions,因为 Promise 形成一个扁平链。

其次,promise 不能很好地处理控制流。即使是像 if-then 语句这样简单的事情也会变得粗糙。

他们比 imo 的大多数其他选项做得更好。请参阅简单 if 语句的 this example

我真正想要的是某种方式来做到这一点:

this.backdrop('backdrop-1.png', { effect: 'fade-in', duration: 1000, sync: true });
waitUntilAllPromisesAreResolved();
this.backdrop('backdrop-2.png', { effect: 'fade-in', duration: 500 });

但那是白日梦,不是吗?

不一定 - 有生成器,最终会有 async/await。这些允许您在异步函数中使用“同步”(正常)控制流语句:

(async function() {
    await this.backdrop('backdrop-1.png', { effect: 'fade-in', duration: 1000});
    await this.backdrop('backdrop-2.png', { effect: 'fade-in', duration: 500 });
    console.log("both done");
}()); // returns a promise

不过,您必须使用 ES6/ES7 转译器。

然而,即使是简单的

this.backdrop('backdrop-1.png', { effect: 'fade-in', duration: 1000, sync: true });
this.backdrop('backdrop-2.png', { effect: 'fade-in', duration: 500 });

今天非常有可能在第一个效果之后动画第二个效果!您只需在this 上放置一个内部动画队列,backdrop 方法将添加到该队列中,而不是立即执行。例如,jQuery 确实使用了这种方法,并且非常流行!

【讨论】:

  • Bergi,你是冠军!该项目已经在使用 Babel,因此很容易集成它。
  • 很好的答案!我将其称为内部 而不是队列,因为它将是一系列 异步 操作,其中一个在前一个结束时开始。这样的链甚至可以用 Promise 来实现。
  • @jib:我想说这取决于实现(功能、可见性、管理它的人),它看起来更像队列还是更像链。但是,是的,您可以使用承诺链来做到这一点。
猜你喜欢
  • 2018-06-26
  • 2016-01-10
  • 2014-03-12
  • 2015-01-28
  • 2017-12-12
  • 2017-05-25
  • 2022-01-17
  • 1970-01-01
相关资源
最近更新 更多