-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
core.Promise should not fall back to native Promise when native implementation suffers from V8 bug 4162 #78
Comments
Doesn't the spec say to explicitly enqueue the then resolve task? It does say to access the then property synchronously and detect if it is callable or not. But the enquement is deferred. I may be wrong, just responding from memory and from my phone between flights. Cc @domenic as he will shed a definitive light on the situation. |
Yes, getting the then (D) is synchronous. Invoking the then (A) for the purpose of following its resolution is not.
That's why I only said "D" must happen before "Sync end". (And A or D being printed multiple times, once for each reaction registered with .then(), is the much more serious result of the bug.) |
For reference, this is Chrome's native Promise's output for that example:
Note that all the comparisons are false - both count and count2 are two instead of one (one for each call to Here's the output from FF Nightly (native Promise):
This is the output from core-js 0.9.15:
As you can see, A is being printed synchronously which is a bug in core-js (but separate from this one). (This is actually correct behavior per Promises/A+ spec which is perhaps why core-js does it? I don't know.) |
Ah. Then misread your bug, and my comment seems to confirm what you describe. So feel free to ignore me :p |
This is correct behavior by Promises/A+, \cc @getify this bug still in @stefanpenner can you help adapt About v8 bug - proposed test based on getter and will not work in ES3 engines, but |
Yeah, I figured that was the reason core-js was doing that. |
(Also, the fact that the order of reactions is different between FF and core-js - F-G-B-C vs B-C-F-G - is also probably because A is getting run too soon, so the fix to call thenable.then asynchronously will probably also fix the wrong order of reactions.) |
If Object.defineProperty doesn't exist, then it wouldn't be V8, right? I'm okay that the common case of running in V8 with the bug is detected and handled, so I don't think core-js needs to try hard to detect the bug in other runtimes. Native global Promise shouldn't exist in that case either, so |
I'm confused by this thread. Is the assertion that there's a conflict between Promises/A+ and ES6 Promises? If so, that's a pretty significant problem. Can you please explain a simpler test case of what you think is different between Promises/A+ compliance and ES6 Promises compliance? |
OK, I think I am digging in and starting to glimpse a little bit what this bug is about. Let me make some observations to check if I understand the concern:
|
After @getify comment I'm confused. FF and V8 |
Well, I'm confused too. I'm not positive what's supposed to happen here. I do know that I've now tried to defer the If I defer it with |
NPO as currently released is Promises/A+ compliant. And it invokes
|
I'm pretty sure rsvp and es6 satisfy both a+ and the spec here. I'll verify when I'm at the office |
Looking more closely at the A+ test suite starting here, I don't see it testing the sequencing of whether So is this that Promises/A+ doesn't care if you call it synchronously or not? Or is it that Promises/A+ expects synchronous calling (as the wording implies) but has no tests to verify it? @domenic, can you please comment specifically on that? When I first wrote NPO, I was deeply concerned that there were additional ES6 requirements (the whole Promise API) that Promises/A+ tests were not covering. I enlisted @smikes to suffer through the pain of figuring out a more comprehensive test suite. I don't know what happened with that, but as I said earlier, I thought I recalled it stalled at an impasse around lack of a reliable scheduling API. However, this issue at present is not one I anticipated: that there is wording in Promises/A+ which is contradicted by ES6, and moreover, that there's wording in Promises/A+ which was not tested. |
(It is not my intent to turn this bug into a discussion about whether the thenable's then is to be invoked synchronously or asyncronously. V8's Promise is broken because it invokes the thenable's then multiple times, once for each reaction registered to the promise, and that is how I discovered it.)
It would seem so. The former asks thenable's then to be gotten and invoked synchronously. The latter asks thenable's then to be gotten synchronously and invoked asynchronously.
As I said in the V8 bug linked in the OP, without looking at the implementation, I'm assuming it defers checking what value a promise was resolved with until evaluating reactions. Such an algorithm would lead to the same observed behavior as the ES6 spec if the resolution was not a thenable, but for thenables it leads to different behavior. Note again that I'm talking about the bug of invoking the thenable's then multiple times. I'm more concerned about that one.
If you believe that p is to invoke the thenable's then asynchronously to follow its resolution, that pushes the resolution of its reactions down by a tick, putting them after F and G's resolutions via p2. p2 was rejected while trying to get the thenable's then, so it happened synchronously, and so F and G's resolutions are queued to the next tick, the same one as where p invokes its thenable's then. I wrote a small Promise implementation overnight by mostly following the ES6 spec verbatim (I ignored some of the subclassing-specific / interop stuff but promises-aplus-tests also doesn't care about that). It gives the same result with the babel example in the OP as Firefox, so there's that. It also passes all promises-aplus-tests. I guess NPO has some other bug that causes 10 tests to fail for you? |
One issue was that in order to land more tests of NPO we'd be testing things (internals) NPO is explicitly not compatible with. The other side is that when we looked at including all of promises/A+ (over 800 tests if I recall correctly) it didn't look like it was worth the trouble, and we had concerns about bootstrapping. /cc @bterlson @domenic for their input On Tue, Jun 9, 2015 at 10:22 AM, Kyle Simpson [email protected]
|
I've spent all day trying to get NPO to run I'm also getting different test suite failures every single time I run it, so that makes it basically impossible to figure out what's wrong. Test suites with timers are bullshit. Anyway, I guess at this point NPO has a bug but I don't know how to fix it. Perhaps someone could file an issue at the NPO repo about it. But unless someone else can figure out how to fix it, I don't expect there to be any fix any time soon. |
skimming over either of these two repos, maybe help inspire a solution for you: |
Maybe its worth a collective effort to port promise/a+ to something more test262 friendly? I suspect it may be worth it, as continuing to grow and audit a single compliance suite has nice value. That being said, it won't be a trivial task. |
The issue is that all the browsers are already running the Promises/A+ tests as part of their test suite and so duplicating that into test262 isn't terribly useful. It has theoretical benefits for e.g. new JS engines but in practice it's not worth the work. |
Ah ok. Thanks |
I don't understand how v8 can have the bug listed in the OP (resolving The same way that v8 can be "compliant" but still have that bug seems to be how something like NPO can be compliant but have the sync/async Especially since my usage of the A+ test suite is totally falling over on itself every time I run it, I don't trust the tests (or the notion of "compliance") at all anymore. It's theater. |
It also would benefit any library/framework that's trying to actually be fully compliant with ES6 Promises if there weren't multiple scattered test suites to try to keep up with. And of course if the one test suite actually tested everything it was supposed to. |
Ya, this would be prevented by a unified test. @domenic i do think it would be worth while, especially since the current state of things may indicate some gap. Maybe someones intern can start the process? |
This thread is pretty toxic so I'd appreciate not being @-mentioned in it any more. |
I'll bow out too. |
Fixed in |
https://code.google.com/p/v8/issues/detail?id=4162
Quoted from that bug:
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise-resolve-functions states that when resolving a Promise with a value, it must try to see immediately if the value is a thenable or not, and if it is, invoke it. So the following code:
must print "Invoking then..." immediately (not synchronously, but next tick or so).
On Chrome dev (V8 4.5.16) / io.js (V8 4.2.77.20), this prints nothing.
The same thing happens if it was instead resolved with a thenable where even accessing the getter should print something.
This will also print nothing (in this case it should be printed synchronously).
I'm guessing V8 is deferring checking whether it's a thenable or not since there are no reactions registered to p with p.then(...).
If I then do
now "Invoking then..." / "Getting then..." get printed, and console.error is invoked with the error thrown by the thenable's body. Unfortunately this leads to the second (more serious) bug - that multiple such calls to p.then will print "Invoking then..." / "Getting then..." multiple times! Effectively the thenable's code is getting run once each time a reaction is registered using p.then, which is very bad.
(Promise.resolve() has the same bug.)
core-js's own Promise implementation is fine, but since it falls back to native Promise if that is found, it becomes vulnerable to this.
This affects Babel too. For example, compare this example's output in a browser that doesn't support native Promise with Chrome / node 0.12. (The spec requires that "A" and "D" be printed only once, that "D" be printed before "Sync end", and that all the comparisons be true).
For the fix, the check for
useNative
could do this in addition to what it already does:The text was updated successfully, but these errors were encountered: