Promise resolution handler fires before synchronous constructor stack has finished.

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Promise resolution handler fires before synchronous constructor stack has finished.

#!/JoePea
I feel like I'm going crazy, but I have a class hierarchy, and one of
the constructors in the hierarchy defers some logic to a microtask,

```js
// class Foo
constructor() {
  Promise.resolve().then(() => {
    this.methodThatSubclassOverrides()
  })
}

methodThatSubclassOverrides() {}
```

and in the subclass there is

```js
// class Bar extends Foo
constructor() {
  super()
  this.foo = 123
}

methodThatSubclassOverrides() {
  console.log(this.foo) // should be "123"
}
```

You'd think the output should be "123" because the deferred code will
run after construction is complete.

However, in my current project, the promise deferral seems to run
before the construction returns to the Bar constructor, thus this.foo
is not set, and calls `methodThatSubclassOverrides` before the Bar
class has a chance to run `this.foo = 123`. So the result of the
console.log is "undefined".

It is totally weird. Do Promises ever resolve before a constructor
stack finishes?

I don't have a simple reproduction at the moment.

- Joe
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Promise resolution handler fires before synchronous constructor stack has finished.

Jordan Harband
When I run this in a node repl, that's exactly what happens - perhaps your simplified example has simplified out the bug?

On Sat, Jul 27, 2019 at 6:57 PM #!/JoePea <[hidden email]> wrote:
I feel like I'm going crazy, but I have a class hierarchy, and one of
the constructors in the hierarchy defers some logic to a microtask,

```js
// class Foo
constructor() {
  Promise.resolve().then(() => {
    this.methodThatSubclassOverrides()
  })
}

methodThatSubclassOverrides() {}
```

and in the subclass there is

```js
// class Bar extends Foo
constructor() {
  super()
  this.foo = 123
}

methodThatSubclassOverrides() {
  console.log(this.foo) // should be "123"
}
```

You'd think the output should be "123" because the deferred code will
run after construction is complete.

However, in my current project, the promise deferral seems to run
before the construction returns to the Bar constructor, thus this.foo
is not set, and calls `methodThatSubclassOverrides` before the Bar
class has a chance to run `this.foo = 123`. So the result of the
console.log is "undefined".

It is totally weird. Do Promises ever resolve before a constructor
stack finishes?

I don't have a simple reproduction at the moment.

- Joe
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Promise resolution handler fires before synchronous constructor stack has finished.

Ranando King
In reply to this post by #!/JoePea
Isn't it always the case that `Promise.resolve()` returns an immediately resolved Promise? That means that the `.then` clause would get executed immediately as well, which is before you have a chance to set `this.foo`.

Seems like what you need to do is something more like this:
```js
// class Foo
constructor() {
  (new Promise((resolve, reject) => { setTimeout(() => { resolve(); },1); })).then(() => {
    this.methodThatSubclassOverrides()
  })
}
```
Done this way, the call to `resolve()` will be thrown onto the run loop for execution later.

On Sat, Jul 27, 2019 at 8:57 PM #!/JoePea <[hidden email]> wrote:
I feel like I'm going crazy, but I have a class hierarchy, and one of
the constructors in the hierarchy defers some logic to a microtask,

```js
// class Foo
constructor() {
  Promise.resolve().then(() => {
    this.methodThatSubclassOverrides()
  })
}

methodThatSubclassOverrides() {}
```

and in the subclass there is

```js
// class Bar extends Foo
constructor() {
  super()
  this.foo = 123
}

methodThatSubclassOverrides() {
  console.log(this.foo) // should be "123"
}
```

You'd think the output should be "123" because the deferred code will
run after construction is complete.

However, in my current project, the promise deferral seems to run
before the construction returns to the Bar constructor, thus this.foo
is not set, and calls `methodThatSubclassOverrides` before the Bar
class has a chance to run `this.foo = 123`. So the result of the
console.log is "undefined".

It is totally weird. Do Promises ever resolve before a constructor
stack finishes?

I don't have a simple reproduction at the moment.

- Joe
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Promise resolution handler fires before synchronous constructor stack has finished.

Jordan Harband
No, that's not accurate - every `.then` always executes on a future tick, never synchronously.

On Sat, Jul 27, 2019 at 11:11 PM Ranando King <[hidden email]> wrote:
Isn't it always the case that `Promise.resolve()` returns an immediately resolved Promise? That means that the `.then` clause would get executed immediately as well, which is before you have a chance to set `this.foo`.

Seems like what you need to do is something more like this:
```js
// class Foo
constructor() {
  (new Promise((resolve, reject) => { setTimeout(() => { resolve(); },1); })).then(() => {
    this.methodThatSubclassOverrides()
  })
}
```
Done this way, the call to `resolve()` will be thrown onto the run loop for execution later.

On Sat, Jul 27, 2019 at 8:57 PM #!/JoePea <[hidden email]> wrote:
I feel like I'm going crazy, but I have a class hierarchy, and one of
the constructors in the hierarchy defers some logic to a microtask,

```js
// class Foo
constructor() {
  Promise.resolve().then(() => {
    this.methodThatSubclassOverrides()
  })
}

methodThatSubclassOverrides() {}
```

and in the subclass there is

```js
// class Bar extends Foo
constructor() {
  super()
  this.foo = 123
}

methodThatSubclassOverrides() {
  console.log(this.foo) // should be "123"
}
```

You'd think the output should be "123" because the deferred code will
run after construction is complete.

However, in my current project, the promise deferral seems to run
before the construction returns to the Bar constructor, thus this.foo
is not set, and calls `methodThatSubclassOverrides` before the Bar
class has a chance to run `this.foo = 123`. So the result of the
console.log is "undefined".

It is totally weird. Do Promises ever resolve before a constructor
stack finishes?

I don't have a simple reproduction at the moment.

- Joe
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss