Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue causes browser to become unresponsive when createElement is called with Promise-returning function #6558

Closed
DanielRosenwasser opened this issue Sep 9, 2017 · 9 comments

Comments

@DanielRosenwasser
Copy link

Version

2.4.2

Reproduction link

https://jsfiddle.net/2pbthd1v/

Steps to reproduce

When calling createElement, pass a function that returns a promise which resolves to a Vue options bag.

For example:

<div id="app">
  <p>{{ message }}</p>
</div>
var options = {
  template: '<div id="replacement">Hello!!</div>',
}

new Vue({
  el: "#app",
  render(h) {
    return h(() => new Promise(r => r(options)));
  }
});

What is expected?

Either something useful or an error message.

What is actually happening?

The entire page stops responding.


This was part of the .d.ts test suite. I wanted to see if a test case was legitimate, but I ended up finding that it triggers some sort of bad behavior.

@HerringtonDarkholme
Copy link
Member

Thanks! This is a valid bug. It freezes browsers and node.

@posva
Copy link
Member

posva commented Sep 10, 2017

I don't think it is a bug, createElement isn't meant to work with Promises, right?

@HerringtonDarkholme
Copy link
Member

It doesn't matter if we need to accept Promise as API. We should not freeze browser or node server when users give Vue wrong input.

@posva
Copy link
Member

posva commented Sep 10, 2017

Oh, yeah I agree with that, it should be fixed if possible, it's unreasonable to freeze the platform 😆 . The reason I'm saying it's not a bug is because from my perspective a bug is a situation not working while it should

edit: I misread the code! Got tricked by the syntax, I thought the promise was using the call of h not the other way around 😵

@HerringtonDarkholme
Copy link
Member

Preliminary investigation shows Vue relies on the function as context to resolve async component.

In this case, render function will always return a new function instance so the handle Vue attaches to the async component function is lost. So Vue will think the component isn't properly resolved.

The fix is simple, move the inline arrow function outside, with a stable identifier var asyncComp = () => Promise.resolve(option) will fix this. Because Vue can find the context it previously attaches to the function.

I guess really no one is using this API. Also the solution to fix it isn't clear to me :/

@yyx990803
Copy link
Member

Exactly what @HerringtonDarkholme said - when the Promise resolves, it will cause the current component to re-render, resulting in a new async factory function, thus entering an infinite update loop.

I also don't see a simple fix to this, but this is not supported usage anyway. I guess what we can do is documenting this behavior in the async component section?

@blocka
Copy link

blocka commented Dec 27, 2017

Is there a workaround? I have a use case where I want to dynamically load a component based on data that is loaded, but I don't want to have to specify each component outright.

Something like:

return h(() => resolveComponent(this.data))

@mandaputtra
Copy link

Can it be documented or maybe log some error when its happen?

@and3k5
Copy link

and3k5 commented Jun 2, 2023

I just fixed a similar case. My website started freezing while using AsyncComponent with Vue 2.7.
I fixed my problem by changing this

new Vue({
    render: function (h) {
        return h(() => import("./my-component.vue"));
    }
}).$mount(selector);

into this

const myComponent = import("./my-component.vue");
new Vue({
    render: function (h) {
        return h(myComponent);
    }
}).$mount(selector);

It seems like storing the component in a variable is enough to avoid the render loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants