Giter Site home page Giter Site logo

Comments (10)

plwalters avatar plwalters commented on September 13, 2024

The handling o the promises being resolved appear to be nested properly to show dependency on the parent from my perspective - if there is a less performant we'd welcome a pull request that demonstrates an issue / solution. A useless return statement isn't less performant as far as I know where as a conditional check with a return to prevent executing a code block would indeed be less performant, so in this regard as long as we have some tests or reasons to improve the code-base it would definitely be accepted.

from dialog.

jods4 avatar jods4 commented on September 13, 2024

The most important aspect of this in my opinion is that this is not idiomatic JS and it makes for really hard to read/understand code.

As a poster child example, of course the useless return on L44 has no impact on perf whether you remove it or not. But it is highly misleading. For a reader like me it implies that you are returning the promise with possible intention to chain it. But in reality, the return value is dismissed since you're not inside a .then() but inside a new Promise((resolve, reject) =>...). It hinders understanding and I'm ready to bet that the person who wrote this code didn't realize that the "returned" promise was actually lost.

The perf aspect is related to memory pressure. Consider a chain of Promises A -> B -> C -> D. Implementation (1) is to do A.then(B.then(C.then(D))) -- what the code does. Implementation (2) is A.then(B).then(C).then(D) -- idiomatic JS.

Observe that in case (1) it is only when the chain is complete (D resolves) that C.then resolves, which makes B.then resolve, which makes A.then resolve. This is what you want, but it means that no promise can be garbage collected before the last one resolves. In some pathological cases that might be a long time.

Case (2) is better because as soon as A resolves it can be GC'ed and so on.

To put it otherwise, in case (1) client code waits on A.then, in case (2) client code waits on .then(D). Very different from GC perspective.

It is also different from a polyfill point of view. A polyfill typically uses setTimeout(f, 0) to schedule promises continuations. In recent Chrome releases, there is a 4ms clamp on setTimeout if it's deeply nested. Observe that in case (1) you unwind all the promises in a long chain at the end, so you are in the "deeply nested" case. In case (2) you only resolve promises in a spread out fashion, which is not affected. In older browsers there is a 10ms clamp on all setTimeout calls, which you will pay as one big fat check at the end of (1) and spread out in (2).

from dialog.

EisenbergEffect avatar EisenbergEffect commented on September 13, 2024

@jods4 We would definitely be interested in a PR to improve this. I wrote that code in haste a month or so ago and hadn't had time to think about it much since. We would appreciate your assistance in improving these issues.

Do you have a resource I can read related to the information you have above? In some of my reading I thought I read that nesting the promises was preferred in order to not lose errors that might occur...but maybe I remembered that wrong or maybe the source I had was wrong.

In any case, we are open to making improvements, especially those that improve performance and lower memory pressure. Please sign our CLA (if you haven't already) and submit a PR. We'd be happy to accept it.

from dialog.

jods4 avatar jods4 commented on September 13, 2024

@EisenbergEffect I have signed the CLA already. If you take PR for this I might have a look at it when I have some time, but that may not be soon as I have a lot of work right now. <_<

Errors flow through the Promise chain. So if you do A.then(B).then(C).then(D).catch(X) you will catch in X any error occuring in the chain. More precisely, if say B throws, the .then(B) promise will reject, which will automatically reject .then(C), which rejects .then(D) and so on until there is a reject handler that catch it in the chain (here X).

Note that you can continue the chain from there. Once the rejection has been handled everything resolves again, e.g.: if you do A.then(B).catch(X).then(C), C will run (that is, assuming X itself does not throw, which would of course reject the .catch(X) promise).

from dialog.

EisenbergEffect avatar EisenbergEffect commented on September 13, 2024

@jods4 Thanks for taking time to write up some information. I know you're busy and thank you for being willing to engage and help us make Aurelia better.

from dialog.

sethlivingston avatar sethlivingston commented on September 13, 2024

Hey guys, this is "Rookie Mistake #1" in Nolan Lawson's (of PouchDB) article here: http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html

I noticed the pyramid right away, too. There is not a performance problem here, but rather a subtle but significant lack of understanding in how promises work. I was in the same boat, so I know first-hand that correcting this will help you use and debug promises more effectively.

from dialog.

EisenbergEffect avatar EisenbergEffect commented on September 13, 2024

Yes, you are 100% correct. This needs to be fixed. @sethlivingston Would you be willing to create a PR to fix it? 😄

from dialog.

sethlivingston avatar sethlivingston commented on September 13, 2024

I have it ready and will submit when #99 gets done. (And please point me somewhere if that's one I can help with, too. I'm assuming it's a general update needed for multiple Aurelia repos, but maybe I'm wrong.)

from dialog.

plwalters avatar plwalters commented on September 13, 2024

#99 is all resolved now, thanks again for contributing @sethlivingston

from dialog.

plwalters avatar plwalters commented on September 13, 2024

Closed by community PR.

from dialog.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.