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

perf: Improve collection-repeat image performance on iOS #3194

Closed
ajoslin opened this Issue Feb 27, 2015 · 34 comments

Comments

Projects
None yet
@ajoslin
Contributor

ajoslin commented Feb 27, 2015

Problems:

  • Setting an un-cached url to an img src gives a 50-200ms freeze on an iPhone 6.
  • iOS UIWebView doesn't properly cache remote image urls. Even after setting once to a url, setting again to the same url will cause a noticeable freeze.

Solutions:

  • Use a web worker to fetch image srcs, convert them to base 64, and give them back as a data-uri.
    • This works.. almost. Once an image has been set to a data-uri once, the WebView does properly cache the uri and reloads it instantly when it's set the next time.

The last solution needed is a way to cache the data uri into the webview beforehand. This will require some experimentation, but it's doable.

@ajoslin ajoslin added this to the 1.0.0-rc1 milestone Feb 27, 2015

@ajoslin ajoslin self-assigned this Feb 27, 2015

@wedgybo

This comment has been minimized.

Show comment
Hide comment
@wedgybo

wedgybo Mar 3, 2015

Just wanted to leave a link to something I looked at previously. It might be worth benchmarking against your web worker code to see how it compares. https://github.com/mallzee/cordova-collection-repeat-image-plugin

wedgybo commented Mar 3, 2015

Just wanted to leave a link to something I looked at previously. It might be worth benchmarking against your web worker code to see how it compares. https://github.com/mallzee/cordova-collection-repeat-image-plugin

@felquis

This comment has been minimized.

Show comment
Hide comment
@felquis

felquis Mar 3, 2015

I tried to create something like this in the past, the main idea was to create a directive to use in wherever I want to use with src or ng-src like:

<img ng-src="my-awesome-pic.png" ion-utils-cache-base64>

And store the base64 in a variable in a some factory or something like that. Just sharing my thoughts on this.

felquis commented Mar 3, 2015

I tried to create something like this in the past, the main idea was to create a directive to use in wherever I want to use with src or ng-src like:

<img ng-src="my-awesome-pic.png" ion-utils-cache-base64>

And store the base64 in a variable in a some factory or something like that. Just sharing my thoughts on this.

@saniyusuf

This comment has been minimized.

Show comment
Hide comment
@saniyusuf

saniyusuf Mar 3, 2015

Contributor

HI @ajoslin I have a component that does something similar that caches the data URI base64string of an image for Ionic apps. I have done that part and are about to integrate the web worker .

@felquis exactly what you are explaining is what I have worked on with some success.

https://github.com/saniyusuf/imagenie

Contributor

saniyusuf commented Mar 3, 2015

HI @ajoslin I have a component that does something similar that caches the data URI base64string of an image for Ionic apps. I have done that part and are about to integrate the web worker .

@felquis exactly what you are explaining is what I have worked on with some success.

https://github.com/saniyusuf/imagenie

@ajoslin

This comment has been minimized.

Show comment
Hide comment
@ajoslin

ajoslin Mar 3, 2015

Contributor

Thanks all!

I also tried the ng-src route. It just wasn't a convincing enough improvement for us to make it part of the framework yet.

I'll look at everything you guys have linked. Thanks a lot. The Cordova plugin route is especially interesting...

Contributor

ajoslin commented Mar 3, 2015

Thanks all!

I also tried the ng-src route. It just wasn't a convincing enough improvement for us to make it part of the framework yet.

I'll look at everything you guys have linked. Thanks a lot. The Cordova plugin route is especially interesting...

@saniyusuf

This comment has been minimized.

Show comment
Hide comment
@saniyusuf

saniyusuf Mar 9, 2015

Contributor

Any update on this?

Contributor

saniyusuf commented Mar 9, 2015

Any update on this?

@ajoslin

This comment has been minimized.

Show comment
Hide comment
@ajoslin

ajoslin Mar 9, 2015

Contributor

We've been at ng-conf and only just returned. I'll be looking into it this week.

Contributor

ajoslin commented Mar 9, 2015

We've been at ng-conf and only just returned. I'll be looking into it this week.

@saniyusuf

This comment has been minimized.

Show comment
Hide comment
@saniyusuf

saniyusuf Mar 9, 2015

Contributor

HI Andrew,
I am really keen to be involved with the web worker. I have put my own
implementation on hold to see what we come up with.

On 9 March 2015 at 15:19, Andrew Joslin notifications@github.com wrote:

We've been at ng-conf and only just returned. I'll be looking into it this
week.

Reply to this email directly or view it on GitHub
#3194 (comment).

Kind Regards
[image: photo]
Sani Yusuf
Co-Founder / CTO, Slapic
http://github.com/saniyusuf
http://stackoverflow.com/users/1714088/sani-yusuf
http://about.me/saniyusuf
http://linkedin.com/in/saniyusuf https://twitter.com/saniyusuf
Get a signature like this:
http://ws-stats.appspot.com/r?rdata=eyJydXJsIjogImh0dHA6Ly93d3cud2lzZXN0YW1wLmNvbS8/dXRtX3NvdXJjZT1leHRlbnNpb24mdXRtX21lZGl1bT1lbWFpbCZ1dG1fY2FtcGFpZ249cHJvbW9fNDUiLCAiZSI6ICJwcm9tb180NV9jbGljayJ9
Click
here!
http://ws-stats.appspot.com/r?rdata=eyJydXJsIjogImh0dHA6Ly93d3cud2lzZXN0YW1wLmNvbS8/dXRtX3NvdXJjZT1leHRlbnNpb24mdXRtX21lZGl1bT1lbWFpbCZ1dG1fY2FtcGFpZ249cHJvbW9fNDUiLCAiZSI6ICJwcm9tb180NV9jbGljayJ9

Contributor

saniyusuf commented Mar 9, 2015

HI Andrew,
I am really keen to be involved with the web worker. I have put my own
implementation on hold to see what we come up with.

On 9 March 2015 at 15:19, Andrew Joslin notifications@github.com wrote:

We've been at ng-conf and only just returned. I'll be looking into it this
week.

Reply to this email directly or view it on GitHub
#3194 (comment).

Kind Regards
[image: photo]
Sani Yusuf
Co-Founder / CTO, Slapic
http://github.com/saniyusuf
http://stackoverflow.com/users/1714088/sani-yusuf
http://about.me/saniyusuf
http://linkedin.com/in/saniyusuf https://twitter.com/saniyusuf
Get a signature like this:
http://ws-stats.appspot.com/r?rdata=eyJydXJsIjogImh0dHA6Ly93d3cud2lzZXN0YW1wLmNvbS8/dXRtX3NvdXJjZT1leHRlbnNpb24mdXRtX21lZGl1bT1lbWFpbCZ1dG1fY2FtcGFpZ249cHJvbW9fNDUiLCAiZSI6ICJwcm9tb180NV9jbGljayJ9
Click
here!
http://ws-stats.appspot.com/r?rdata=eyJydXJsIjogImh0dHA6Ly93d3cud2lzZXN0YW1wLmNvbS8/dXRtX3NvdXJjZT1leHRlbnNpb24mdXRtX21lZGl1bT1lbWFpbCZ1dG1fY2FtcGFpZ249cHJvbW9fNDUiLCAiZSI6ICJwcm9tb180NV9jbGljayJ9

@ajoslin

This comment has been minimized.

Show comment
Hide comment
@ajoslin

ajoslin Mar 10, 2015

Contributor

Working on this today.

Contributor

ajoslin commented Mar 10, 2015

Working on this today.

@saniyusuf

This comment has been minimized.

Show comment
Hide comment
@saniyusuf

saniyusuf Mar 10, 2015

Contributor

Any idea how you intend to do the conversion in the worker since worker
does not have the document object

Contributor

saniyusuf commented Mar 10, 2015

Any idea how you intend to do the conversion in the worker since worker
does not have the document object

@ajoslin

This comment has been minimized.

Show comment
Hide comment
@ajoslin

ajoslin Mar 10, 2015

Contributor

We don't need the document object. I already know how to convert the worker to base64 (I'll have code up later today).

The problem is caching the image before it hits the visible DOM.

Contributor

ajoslin commented Mar 10, 2015

We don't need the document object. I already know how to convert the worker to base64 (I'll have code up later today).

The problem is caching the image before it hits the visible DOM.

@ryanricig

This comment has been minimized.

Show comment
Hide comment
@ryanricig

ryanricig Mar 11, 2015

Hey - also anxiously awaiting this one, we've got an infinite list of images (like Facebook timeline) of unknown heights (until the images load). Currently we've got an ng-repeat being used but we are seeing some memory issues. So we have switched to the new collection-repeat, but as you note, there is a choppy stop-n-go type nature to the scrolling. Excited to see what you guys come up with.

ryanricig commented Mar 11, 2015

Hey - also anxiously awaiting this one, we've got an infinite list of images (like Facebook timeline) of unknown heights (until the images load). Currently we've got an ng-repeat being used but we are seeing some memory issues. So we have switched to the new collection-repeat, but as you note, there is a choppy stop-n-go type nature to the scrolling. Excited to see what you guys come up with.

@felquis

This comment has been minimized.

Show comment
Hide comment
@felquis

felquis Mar 17, 2015

What if we use a plugin (like file-transfer) to literally download the image, and use it as a local image... I think it probably load faster than always reaching an external URL.

felquis commented Mar 17, 2015

What if we use a plugin (like file-transfer) to literally download the image, and use it as a local image... I think it probably load faster than always reaching an external URL.

@wedgybo

This comment has been minimized.

Show comment
Hide comment
@wedgybo

wedgybo Mar 17, 2015

There are performance gains to be had doing that, but they don't make a huge difference. When you start getting crazy with images, even applying a base64 string version of it still stalls the browser because it's painting on the main thread. Even more so if the image has to be scaled to fit the space. The main thing that's going to help this I believe it the native scrolling. Once that becomes standard there will be a lot more time on the main thread for stuff to happen. Then maybe offloading some preloading to service workers or something to keep things smooth.

Another stop gap solution for offloading the scaling is to run an image proxy which is cached by something like cloudfront. We run a simple node server on heroku which will download an image, scale it to the size requested, and serve it with a cache TTL of a few days. That way the majority of the load is handled by the cache for the majority of our users. Then we just created a directive to augment the image tag to calculate the space that needed to be filled by the image and redirected to our image proxy.

wedgybo commented Mar 17, 2015

There are performance gains to be had doing that, but they don't make a huge difference. When you start getting crazy with images, even applying a base64 string version of it still stalls the browser because it's painting on the main thread. Even more so if the image has to be scaled to fit the space. The main thing that's going to help this I believe it the native scrolling. Once that becomes standard there will be a lot more time on the main thread for stuff to happen. Then maybe offloading some preloading to service workers or something to keep things smooth.

Another stop gap solution for offloading the scaling is to run an image proxy which is cached by something like cloudfront. We run a simple node server on heroku which will download an image, scale it to the size requested, and serve it with a cache TTL of a few days. That way the majority of the load is handled by the cache for the majority of our users. Then we just created a directive to augment the image tag to calculate the space that needed to be filled by the image and redirected to our image proxy.

@okonon

This comment has been minimized.

Show comment
Hide comment

okonon commented Mar 17, 2015

@AceLondon

This comment has been minimized.

Show comment
Hide comment
@AceLondon

AceLondon Mar 19, 2015

Have you seen this web worker wrapped in an angular service? Looks promising. https://github.com/FredrikSandell/angular-workers

AceLondon commented Mar 19, 2015

Have you seen this web worker wrapped in an angular service? Looks promising. https://github.com/FredrikSandell/angular-workers

@perrygovier perrygovier modified the milestones: 1.0.0-rc2, 1.0.0-rc1 Mar 20, 2015

@Fayozjon

This comment has been minimized.

Show comment
Hide comment
@Fayozjon

Fayozjon Mar 25, 2015

softBarbarian

http://goohoo.net/bitcoin-forex4you

18.03.2015, 01:50, "softBarbarian" notifications@github.com:Take a look at

—Reply to this email directly or .

Fayozjon commented Mar 25, 2015

softBarbarian

http://goohoo.net/bitcoin-forex4you

18.03.2015, 01:50, "softBarbarian" notifications@github.com:Take a look at

—Reply to this email directly or .

@perrygovier perrygovier modified the milestones: 1.0.0-rc2, 1.0.0-rc3 Mar 30, 2015

@adamdbradley adamdbradley modified the milestones: 1.0.0-rc3, 1.0.0-rc4 Apr 13, 2015

@wootapa

This comment has been minimized.

Show comment
Hide comment
@wootapa

wootapa Apr 30, 2015

Any update on this?

wootapa commented Apr 30, 2015

Any update on this?

@perrygovier

This comment has been minimized.

Show comment
Hide comment
@perrygovier

perrygovier May 4, 2015

Member

Andrew got the web worker to process image data and feed it back to the main thread as base64 data working, but it didn't result in a significant performance boost. It was a great idea, one we'll probably leverage in different ways for Ionic v2, but it didn't help in this case.

Feel free to take a look at Andrew's PR if you want to play around with it, but I don't think we'll be adding this to v1 of Ionic unless we come up with ideas of how to improve the performance further.

Member

perrygovier commented May 4, 2015

Andrew got the web worker to process image data and feed it back to the main thread as base64 data working, but it didn't result in a significant performance boost. It was a great idea, one we'll probably leverage in different ways for Ionic v2, but it didn't help in this case.

Feel free to take a look at Andrew's PR if you want to play around with it, but I don't think we'll be adding this to v1 of Ionic unless we come up with ideas of how to improve the performance further.

@onigetoc

This comment has been minimized.

Show comment
Hide comment
@onigetoc

onigetoc Aug 23, 2015

I see many APP who hide the image when not in view and they reappear when you scroll.
Do you think thant just make in visibility hidden when out of view can change something in performance?

onigetoc commented Aug 23, 2015

I see many APP who hide the image when not in view and they reappear when you scroll.
Do you think thant just make in visibility hidden when out of view can change something in performance?

@salqadri

This comment has been minimized.

Show comment
Hide comment
@salqadri

salqadri Sep 10, 2015

I am seeing the same issue. I try to display images in an ion-scroll and they don't show; I then move the scroll slightly and it shows up. When I pop the view and push into it again the images again don't show even though they were loaded up and showing earlier. Annoyed.
EDIT: Tried the 'collection-repeat' technique and it works amazingly well and solves my issue. Thanks!

salqadri commented Sep 10, 2015

I am seeing the same issue. I try to display images in an ion-scroll and they don't show; I then move the scroll slightly and it shows up. When I pop the view and push into it again the images again don't show even though they were loaded up and showing earlier. Annoyed.
EDIT: Tried the 'collection-repeat' technique and it works amazingly well and solves my issue. Thanks!

@revolunet

This comment has been minimized.

Show comment
Hide comment
@revolunet

revolunet Sep 23, 2015

@salqadri : you mean @wedgybo cordova plugin ?

revolunet commented Sep 23, 2015

@salqadri : you mean @wedgybo cordova plugin ?

@roblav96

This comment has been minimized.

Show comment
Hide comment
@roblav96

roblav96 Sep 25, 2015

take a look at what the team at angular material did to remedy this issue:

angular/material@d68b4f6

roblav96 commented Sep 25, 2015

take a look at what the team at angular material did to remedy this issue:

angular/material@d68b4f6

@louisdoe

This comment has been minimized.

Show comment
Hide comment
@louisdoe

louisdoe Dec 1, 2015

Hi everyone, is this issue still in ionic version 1.1.0 ?
I have a long list in my app using collection-repeat, I am a newbie, what should I do to make perf ?

Thanks

louisdoe commented Dec 1, 2015

Hi everyone, is this issue still in ionic version 1.1.0 ?
I have a long list in my app using collection-repeat, I am a newbie, what should I do to make perf ?

Thanks

@m52go

This comment has been minimized.

Show comment
Hide comment
@m52go

m52go Dec 8, 2015

This issue isn't limited to collection-repeat. The main view on my app is a collection of cards, each with their own background-image set:

<div class="image" style="background-image:url('{{ card.cover_picture }}');">

Just having that background image set slows the app to a crawl (on iOS) whenever navigating to or from that template. I'm using ng-repeat because I only load 15-60 cards into the DOM at any time, but the exact same problem persists with raw HTML (i.e., no ng-repeat or collection-repeat).

The delay seems to increase with the number of cards in the DOM, but it's even perceptible with just 2-3 cards, so I can't work around the issue by limiting the number of elements in the DOM.

Taking that background-image CSS out makes everything normal again. This is a huge problem for me.

EDIT: apparently ng-src on an img tag is supposed to cache but that's not helping.

EDIT 2: after a week of trying everything I could possibly imagine, the delay I was seeing was occurring because the elements in which the images are placed are absolutely positioned. No idea why, but that's what was causing the delay. Sorry. This message can be disregarded as it's no longer relevant to this thread.

m52go commented Dec 8, 2015

This issue isn't limited to collection-repeat. The main view on my app is a collection of cards, each with their own background-image set:

<div class="image" style="background-image:url('{{ card.cover_picture }}');">

Just having that background image set slows the app to a crawl (on iOS) whenever navigating to or from that template. I'm using ng-repeat because I only load 15-60 cards into the DOM at any time, but the exact same problem persists with raw HTML (i.e., no ng-repeat or collection-repeat).

The delay seems to increase with the number of cards in the DOM, but it's even perceptible with just 2-3 cards, so I can't work around the issue by limiting the number of elements in the DOM.

Taking that background-image CSS out makes everything normal again. This is a huge problem for me.

EDIT: apparently ng-src on an img tag is supposed to cache but that's not helping.

EDIT 2: after a week of trying everything I could possibly imagine, the delay I was seeing was occurring because the elements in which the images are placed are absolutely positioned. No idea why, but that's what was causing the delay. Sorry. This message can be disregarded as it's no longer relevant to this thread.

@tgensol

This comment has been minimized.

Show comment
Hide comment
@tgensol

tgensol Mar 16, 2016

I created a directive like this :

<div image="{{item.image}}" set-image></div>

directive('setImage', function () {
  return {
    restrict: 'A',
    link: function (scope, elem, attrs) {
      attrs.$observe('image', function (val) {
        if (val) {
          elem.css('background', 'url("' + val + '") #eee no-repeat center center');
          elem.css('background-size', 'cover');
        }
        else{
          elem.css('background', '#eee');
        }
      });
    }
  };
})

And the performance issue is no longer here. Hope this help

tgensol commented Mar 16, 2016

I created a directive like this :

<div image="{{item.image}}" set-image></div>

directive('setImage', function () {
  return {
    restrict: 'A',
    link: function (scope, elem, attrs) {
      attrs.$observe('image', function (val) {
        if (val) {
          elem.css('background', 'url("' + val + '") #eee no-repeat center center');
          elem.css('background-size', 'cover');
        }
        else{
          elem.css('background', '#eee');
        }
      });
    }
  };
})

And the performance issue is no longer here. Hope this help

@onigetoc

This comment has been minimized.

Show comment
Hide comment
@onigetoc

onigetoc Mar 16, 2016

Do blob image do a difference rather than base64?
I'm creating a Chrome app and it do not accept external image. so i had to create a directive to transform image to blob or image to base64.
https://gist.github.com/onigetoc/928f11e4127f81434b46

onigetoc commented Mar 16, 2016

Do blob image do a difference rather than base64?
I'm creating a Chrome app and it do not accept external image. so i had to create a directive to transform image to blob or image to base64.
https://gist.github.com/onigetoc/928f11e4127f81434b46

@ihuseynoff

This comment has been minimized.

Show comment
Hide comment
@ihuseynoff

ihuseynoff Aug 31, 2016

I have noticed that it was solved for ionic 2. Is there any improvement for ionic 1?

ihuseynoff commented Aug 31, 2016

I have noticed that it was solved for ionic 2. Is there any improvement for ionic 1?

@khkmalki

This comment has been minimized.

Show comment
Hide comment
@khkmalki

khkmalki Oct 24, 2016

Up Up

Anything here ?

khkmalki commented Oct 24, 2016

Up Up

Anything here ?

@Rakonda

This comment has been minimized.

Show comment
Hide comment
@Rakonda

Rakonda Nov 12, 2016

Interesting in any update

Rakonda commented Nov 12, 2016

Interesting in any update

@tgensol

This comment has been minimized.

Show comment
Hide comment
@tgensol

tgensol Nov 12, 2016

My directive is working very fine on my mobile app, did you try it ?

tgensol commented Nov 12, 2016

My directive is working very fine on my mobile app, did you try it ?

@mnewmedia

This comment has been minimized.

Show comment
Hide comment
@mnewmedia

mnewmedia Nov 15, 2016

same as @tgensol but bit modified for my needs

<img ng-src="{{imagePath}}" collection-image image="{{imagePath}}">
angular.module('starter').directive('collectionImage', function () {
    return {
        restrict: 'A',
        link: function (scope, ele, attrs) {
            attrs.$observe('image', function (val) {
                ele.src = val;
            });
        }
    };
});

mnewmedia commented Nov 15, 2016

same as @tgensol but bit modified for my needs

<img ng-src="{{imagePath}}" collection-image image="{{imagePath}}">
angular.module('starter').directive('collectionImage', function () {
    return {
        restrict: 'A',
        link: function (scope, ele, attrs) {
            attrs.$observe('image', function (val) {
                ele.src = val;
            });
        }
    };
});
@ihuseynoff

This comment has been minimized.

Show comment
Hide comment
@ihuseynoff

ihuseynoff Nov 15, 2016

None of the directives provide smooth performance as ionic 2 provide.

ihuseynoff commented Nov 15, 2016

None of the directives provide smooth performance as ionic 2 provide.

@tgensol

This comment has been minimized.

Show comment
Hide comment
@tgensol

tgensol Nov 15, 2016

Sure, but you cannot compare angularJS1 to angularjs 2 I guess

tgensol commented Nov 15, 2016

Sure, but you cannot compare angularJS1 to angularjs 2 I guess

@khkmalki

This comment has been minimized.

Show comment
Hide comment
@khkmalki

khkmalki Nov 15, 2016

Hi, I have notice there is a problem with scrolling in general especially on iPhone 5s wither it is Hybrid or Native App. You have to handle this on your own. Some remove image temporarily when it is not on the current view, others divide it into pages instead of scrolling 1 page. You can write an algorithm that handle massive numbers of elements, then sell it, I mean share it.

Sent from my iPhone

On Nov 15, 2016, at 5:53 AM, Thibaut notifications@github.com wrote:

Sure, but you cannot compare angularJS1 to angularjs 2 I guess


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

khkmalki commented Nov 15, 2016

Hi, I have notice there is a problem with scrolling in general especially on iPhone 5s wither it is Hybrid or Native App. You have to handle this on your own. Some remove image temporarily when it is not on the current view, others divide it into pages instead of scrolling 1 page. You can write an algorithm that handle massive numbers of elements, then sell it, I mean share it.

Sent from my iPhone

On Nov 15, 2016, at 5:53 AM, Thibaut notifications@github.com wrote:

Sure, but you cannot compare angularJS1 to angularjs 2 I guess


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.

@ionic-issue-bot ionic-issue-bot bot locked and limited conversation to collaborators Sep 9, 2018

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.