-
-
Notifications
You must be signed in to change notification settings - Fork 929
m.request not redrawing automatically in Chrome #2426
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
Comments
You might try rc6 ( The problem is the redraw occurs after the One solution is to use promises: oninit ({state}) {
m.request("https://reqres.in/api/users/2"),then(response => {
state.user = response.data;
}) // Redraw happens after this chain resolves.
} Another is to manually redraw: async oninit(vnode) {
let response = await m.request({
url: "https://reqres.in/api/users/2",
background: true
});
this.user = response.data;
m.redraw();
} |
@spacejack Just tried A couple of things:
If that is the case, then why does it work in other browsers, just not Chrome?
Well an async function is just syntax sugar (to some extent) for promises, no? My async function should be semantically equivalent to something like this: oninit(vnode) {
return m.request("https://reqres.in/api/users/2").then(response => {
this.user = response.data;
});
}
I decided to verify that indeed Chrome follows this behavior, and it appears that it does. This example works in both Chrome and Firefox in the way you expect: const test = async () => {
await { // not a promise, but does have a `then` method
then(callback) {
setTimeout(() => callback(), 5000);
}
};
alert("slept!");
};
test(); |
Sorry, I ran into a similar problem a while ago and maybe my assessment of it was wrong. I don't understand why it works in other browsers either. What if you try async oninit(vnode) {
this.user = (await m.request("https://reqres.in/api/users/2")).data;
} I was under the impression that this should work in v2: let response = await m.request("https://reqres.in/api/users/2");
this.user = response.data; If not I think it would be a bug. |
Nope, that behaves the same way. Still works in Firefox, still doesn't work in Chrome. You should be able to open the HTML file I provided in the issue description to reproduce yourself too, if that helps. Like I said, I did some poking around in the debugger and it seemed like something odd was going on with setting up the finalizer for |
Here is a flems repro of your example with Mithril 2.0-rc6. If you swap to the Promise-based oninit it works. I think the reason that |
First, I'm seeing the same issue on v1.x with Chrome. That repro lets you compare both through a couple simple buttons. Second, I strongly suspect a V8 bug here. It repros even without the DOM. If it's not a V8 issue, then I suspect it's either a spec bug or a design limitation I can't really work around. I've filed https://bugs.chromium.org/p/v8/issues/detail?id=9349 to track this. |
@isiahmeadows was wondering, with redraws being async (by way of RAF) does This would break cases where you're relying on it to defer the redraw until another long-running (i.e., longer than RAF) promise is appended to the chain (and you might need to use |
@spacejack Yes. The event loop in modern browsers obviously can't run animation callbacks while draining the microtask queue, because those are always drained at highest priority as a single step, and as per spec they aren't handled as a normal "task queue" like the task queues for requests and timers are. However, you could schedule a Here's the relevant parts of the spec:
|
Figured it out: V8 is actually doing the right thing here, but nobody else is and so that's why this shows up in Chrome, but not Firefox or Safari: tc39/ecma262#1577. It's exceedingly subtle, but it comes down to this:
Gotta love spec bugs and implementation divergence. 🙂 The proper workaround is two-part and very subtle:
|
Nice work @isiahmeadows. |
Good investigation! The solution is way above my head, but still interesting to read. |
@sagebind If you'd like to know a bit more about the background leading up to my fix, I wrote this Twitter thread on it, targeting a less technical audience that includes non-programmers. |
Uh oh!
There was an error while loading. Please reload this page.
Mithril Version: 1.1.6
When using
m.request
inside anoninit
lifecycle method that returns a promise, Mithril does not redraw automatically in Chrome like it should when the request finishes and the promise resolves. It does work in Firefox and Safari.Expected Behavior
Current Behavior
Possible Solution
I tried stepping through Mithril in the browser debugger on Chrome and Firefox to figure out what is different between the two, and in Chrome it seems like this callback is never getting invoked: https://github.com/MithrilJS/mithril.js/blob/v1.1.6/request/request.js#L20-L26. Maybe Chrome does not allow reassigning
then
on a nativePromise
object? If that is the case, maybe there's some other way of doing this, like creating a new promise and wrapping the old one.As a workaround, I am calling
m.redraw()
manually at the end of my oninit lifecycle in my actual application (company Intranet project).Steps to Reproduce
Here is an example tiny app that reproduces the problem:
In Firefox, this shows
Loading...
for a short time and then displays user information. On Chrome, this displaysLoading...
forever unless you callm.redraw()
manually in the JavaScript console.Context
Additional Information
Your Environment
The text was updated successfully, but these errors were encountered: