Wait until all promises are resolved in JavaScript

时间:2015-07-28 17:16:03

标签: javascript promise

I'm not optimistic there's a way to do this, but I wanted to put the question out there. The situation: I'm writing a JavaScript game engine that's tailored for novice programmers. I want the primary scripting interface to be as simple and accessible as possible. Ideally, scripts would end up looking something like this:

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

In this scenario, the first backdrop would fade in completely over the course of one second, then the second backdrop would fade in synchronously. The problem? JavaScript will try to execute the second command before the first has completed.

Now, the right way to handle this would be to use promises. Something like:

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

Which is totally an option. (In fact, it's probably what I'll have to settle for.) But there are two reasons why I'd prefer not to go this route. First, it adds a lot of extra verbiage to what is meant to be a simple script. I'd like this to look unintimidating to new programmers, and all those nested functions are gonna start looking scary. Secondly, promises don't handle control flow super well. Even something as simple as an if-then statement will get gnarly.

What I'd really like is some way to do this:

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

But that's a pipedream, isn't it? If you can think of a way to make that real, I'd love to hear it.

1 个答案:

答案 0 :(得分:2)

  

它为简单的脚本添加了许多额外的措辞。我希望这对新程序员来说无所畏惧,所有这些嵌套函数都会开始变得吓人。

嗯,它比魔术完成的剧本要好得多(当然可以,见下文)。大多数新手都能够弄清楚then做了什么,但是他们无法识别魔法 - 当某些东西不起作用时,他们会感到很困惑。

顺便说一下,当你使用promises而不是回调时,你几乎应该never have to nest functions,因为承诺会形成扁平链。

  

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

他们比大多数其他选项都做得更好。请参阅简单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 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确实使用这种方法,它非常受欢迎!