aaronc / freactive

High-performance, pure Clojurescript, declarative DOM library
http://documentup.com/aaronc/freactive
Eclipse Public License 1.0
387 stars 27 forks source link

Create polyfills for supporting older browsers #4

Open aaronc opened 9 years ago

aaronc commented 9 years ago

Good polyfills for things like requestAnimationFrame, addEventListener, etc. to support older browsers where feasible

ul commented 9 years ago

Om uses

(if (exists? js/requestAnimationFrame)
              (js/requestAnimationFrame #(render-all state))
              (js/setTimeout #(render-all state) 16))

so I think it fits most cases.

(def request-animation-frame
  (if (exists? js/window.requestAnimationFrame)
     js/window.requestAnimationFrame
    #(js/window.setTimeout % 16)))
ul commented 9 years ago

addEventListener polyfill could be borrowed from Dommy:

(if (.-addEventListener elem)
        (.addEventListener elem (name actual-type) canonical-f)
        ;; For IE < 9
        (.attachEvent elem (name actual-type) canonical-f))))
(if (.-removeEventListener elem)
        (.removeEventListener elem (name actual-type) canonical-f)
        ;; For IE < 9
        (.detachEvent elem (name actual-type) canonical-f))))
aaronc commented 9 years ago

Sounds good. Would you want to make a pull request so you'll get credit? ;)

aaronc commented 9 years ago

We could also try to capture vendor prefixes and make sure there's a performance timestamp (although I'm not really sure this part is necessary): https://gist.github.com/timhall/4078614

aaronc commented 9 years ago

I think attachEvent might need the "on" prefix: http://stackoverflow.com/questions/2657182/correct-usage-of-addeventlistener-attachevent.

I also intend to allow people to optionally plug-in goog.events or another handler system if they want a well tested event subsystem. For instance one could require freactive.gevents and then call use-goog-events! We could also just do this by default - but possibly some would complain about increased size...?

ul commented 9 years ago

Yes, I will make pull request after we come to agree of preferred solution. What about size increase on using google events — it is to be tested, may be it will be negligible.

ul commented 9 years ago

We could also try to capture vendor prefixes and make sure there's a performance timestamp (although I'm not really sure this part is necessary): https://gist.github.com/timhall/4078614

I think this solution is overengineering with doubtful value. We must not rely on any particular fps — so we don't need precise timing. Also, if our render cycle is too heavy then it seems that logic is quite heavy too and we want to give it 16ms to proceed, not to shrink its time. And, if our render cycle is heavy, we should remember that setTimeout polyfill does not stop rendering when tab is inactive (requestAnimationFrame does), so we don't want to make high cpu load when inactive, so empirical 16ms pause is also good in this case

I think attachEvent might need the "on" prefix

Yes, but now I think that we have no necessity to support attachEvent. IE8 has too many problems aside of this one to drop its support, and IE9+ has addEventListener, so we have no problems with it.

aaronc commented 9 years ago

So I agree with what you're saying about precise timing. We could just try to pull in the vendor prefixes and if not, use the setTimeout with 16ms like Om.

ul commented 9 years ago

17 polyfill arrived ;-)

i will investigate plugging of google closure events these days and then report back, m.b. in a new issue or pull request

aaronc commented 9 years ago

Okay, sounds good. I think that polyfill looks pretty good so I'm going to go ahead and merge it.

ul commented 9 years ago

I did :advanced compile of example from freactive readme using addEventListener vs goog.events/listen

ul@cybercraft ~/S/f/bench> du *
176K    goog-frk.min.js
172K    native-frk.min.js

goog.events adds about 4K, which is about 2.3%. I think it is not much, especially keeping in mind that it is minimal example, real app will be bigger. Also, we can make it pluggable. What is the best way to make this? Allow to pass listen! and remove-event-listener! (hmmm... m.b. unlisten! will be more consistent & short?) as parameters to mount?

aaronc commented 9 years ago

Cool. How much is that gzipped?

We can just have a separate namespace that calls set! on the listen! var - not very Clojure-like I know, but I think it's okay.

On Sunday, November 23, 2014, Ruslan Prokopchuk notifications@github.com wrote:

I did :advanced compile of example from freactive readme using addEventListener vs goog.events/listen

ul@cybercraft ~/S/f/bench> du * 176K goog-frk.min.js 172K native-frk.min.js

goog.events adds about 4K, which is about 2.3%. I think it is not much, especially keeping in mind that it is minimal example, real app will be bigger. Also, we can make it pluggable. What is the best way to make this? Allow to pass listen! and remove-event-listener! (hmmm... m.b. unlisten! will be more consistent & short?) as parameters to mount?

— Reply to this email directly or view it on GitHub https://github.com/aaronc/freactive/issues/4#issuecomment-64130328.

ul commented 9 years ago
ul@cybercraft ~/S/f/bench> du *
48K goog-frk.min.js.gz
44K native-frk.min.js.gz

delta is the same =)

aaronc commented 9 years ago

Is that your whole project?

On Sunday, November 23, 2014, Ruslan Prokopchuk notifications@github.com wrote:

ul@cybercraft ~/S/f/bench> du * 48K goog-frk.min.js.gz 44K native-frk.min.js.gz

delta is the same =)

— Reply to this email directly or view it on GitHub https://github.com/aaronc/freactive/issues/4#issuecomment-64132591.

ul commented 9 years ago

No, it is example from freqctive README. Give 5 minutes, I will post benchmark using my project codebase.

ul commented 9 years ago

Hmmm... I'm already using goog.events for routing, so size doesn't changed with listen switch. After removing events from routing it... also without change, m.b. one of dependencies uses goog.events:

ul@cybercraft ~/M/m/bench> du -b *
474370  goog.js
474373  native.js
ul@cybercraft ~/M/m/bench> gzip *
ul@cybercraft ~/M/m/bench> du -b *
121756  goog.js.gz
121757  native.js.gz
aaronc commented 9 years ago

So, I looks like freactive by itself isn't that heavyweight right now.

On Sunday, November 23, 2014, Ruslan Prokopchuk <notifications@github.com javascript:_e(%7B%7D,'cvml','notifications@github.com');> wrote:

Hmmm... I'm already using goog.events for routing, so size doesn't changed with listen switch. After removing events from routing it... also without change, m.b. one of dependencies uses goog.events:

ul@cybercraft ~/M/m/bench> du -b 474370 goog.js 474373 native.js ul@cybercraft ~/M/m/bench> gzip ul@cybercraft ~/M/m/bench> du -b * 121756 goog.js.gz 121757 native.js.gz

— Reply to this email directly or view it on GitHub https://github.com/aaronc/freactive/issues/4#issuecomment-64133392.

ul commented 9 years ago

created PR #21 as goog.events topic continuation

hura commented 9 years ago

Core.async uses goog.async.nextTick:

https://github.com/google/closure-library/blob/master/closure/goog/async/nexttick.js

https://github.com/clojure/core.async/blob/422f8b25f0c4d5e3aea5113436c735e553422be7/src/main/clojure/cljs/core/async/impl/dispatch.cljs#L29

See the comments in goog.async. Works down to IE6.

HTH

ul commented 9 years ago

https://github.com/google/closure-library/blob/master/closure/goog/async/nexttick.js#L15

/**
 * @fileoverview Provides a function to schedule running a function as soon
 * as possible after the current JS execution stops and yields to the event
 * loop.
 *
 */

requestAnimationFrame has a little bit another purpose

hura commented 9 years ago

Doh. Ignore this then. I was too quick with the post. Sorry for the noise.

ul commented 9 years ago

No problem, you are welcome!

hura commented 9 years ago

Let me try this again. This should be it:

https://github.com/google/closure-library/blob/master/closure/goog/async/animationdelay.js

ul commented 9 years ago

Yes, looks like it is the one, thank you. @aaronc, what do you think?