Examples are simplified / not actual framework code, but to illustrate the point.

In v1, to support async hooks, we’d have to make everything async and do the equivalent of this in the controller:

await this.viewModel.bind(); this.isBound = true; this.doNextThing();

Whole method has to be async (or everything needs to be wrapped in Promise.resolve - either way, we get the full overhead even in sync situations)

Here’s what the process boils down to in v2:

const result = this.viewModel.binding(); if (result instanceof Promise) { return result.then(this.doNextThing); } else { return this.doNextThing(); }

We’ve split lifecycle logic up into methods/functions in such a manner that we can use conditional sync/async continuation.

Everything stays synchronous while being able to deal with promises whenever they show up. Even then it stays synchronous before and after awaiting the promise.

We can’t do this in v1 without breaking stuff and running into issues with the task queue. In v2 it’s all rewritten from the ground up to accommodate for this and other things.