5

I'm new to js. Please, don't kick painfully. I have this code

    window.onresize=function() {alert(1);};

When I resize any browser`s window, this function fires twice. Why? And how to rewrite this code that code will fire once.

Thanx in advance.

dreamweiver
  • 6,002
  • 2
  • 24
  • 39
macloving
  • 1,227
  • 1
  • 18
  • 22

4 Answers4

10

You need a timeout to bundle the resize events.

var res;
window.onresize=function() {
    if (res){clearTimeout(res)};
    res = setTimeout(function(){console.log("resize triggered");},100);
};

live Example

Christoph
  • 50,121
  • 21
  • 99
  • 128
  • `100` is too long. A user can fire two legitimate resize events. You could even argue that any timeout is too long. In theory you could programatically resize the window to generate events with arbitrary intervals. – Halcyon May 19 '15 at 12:46
  • @Halcyon I think, you misunderstood the question. The goal is to supress all subsequent resize events (which however still belong to the same resize). It heavily depends on the scenario, but given a normal event of a user resizing his browser in a normal way, one could argue, whether 100ms is perhaps too low, but certainly not too much. – Christoph May 19 '15 at 13:52
  • 1
    My point is that debouncing using a timeout is at least a little bit inaccurate. In my opinion the better way to debounce is checking the dimension of the window. If the dimension doesn't change you can safely discard the resize event. The timeout is good, but there is a better way. – Halcyon May 19 '15 at 14:09
  • Sorry, but I disagree - your approach means a huge computational overhead which might not be feasible when working with a lot of resizing events. Also, it's concept does not seem to work - If the dimension does not change, it also won't emit a resize event (after all, that's the whole point of this event...)! On the other hand, most browser emit A LOT of resize events (if you're resizing slowly basically for every pixel), which would not get caught by your solution. This however is exactly OP wanted to circumvent. But I'm willing to change my mind, if you provide a working code snippet. – Christoph May 19 '15 at 14:25
  • Maybe there is something you're not aware of. There is a bug (or feature) where browsers fire the resize event _twice_ (probably a resize-start and resize-end). So the resize events always fire in pairs, even if there was only one resize action by the user. I interpret OPs question as pertaining to that. The duplicate event warrants a debounce. The aim of the debounce is not to rate-limit resize events, it's to catch the duplicates - and only the duplicates. Rate limiting in this case also serves as a debounce, but a lossy one. – Halcyon May 19 '15 at 15:20
  • As for the claim that checking the viewport dimension is _"a huge computational overhead"_. I don't think this claim holds (depending on your definition of _huge_), but if you want to you could make a benchmark. I'm checking `window.innerWidth/Height`, to my knowledge there is no additional computation required. If you cache `window` in a local variable (as you should) I doubt the check overhead will amount to much. – Halcyon May 19 '15 at 15:24
  • I guess you are referring to a Chrome Bug ~ 4 years ago, which fired the resize event twice. In that case (where it is infact a duplicate), your solution would have worked. However, it does not handle the general case of browsers firing multiple resize events on one user action (not clicking e.g. the maximize button, but dragging the window). Imo, using timeouts is a more generic solution. – Christoph May 19 '15 at 16:24
6

This event will fire multiple times in different browsers (some once you've finished the the resize, others during).

One way to get around this is to wait a certain amount of time (say half a second) after the event fires, to see if there are further updates. If not, you can proceed with the alert.

e.g.

var resizeTimer;
window.onresize = function(){
    if (resizeTimer){
        clearTimeout(resizeTimer);
    } 
    resizeTimer = setTimeout(function(){
        alert(1);
        }, 500);
};

See it work on this fiddle.

Graham
  • 6,484
  • 2
  • 35
  • 39
2

To prevent function from "firing" the same result more than once when user resize

var doc = document; //To access the dom only once
var cWidth = doc.body.clientWidth;
var newWidth = cWidth; //If you want a log to show at startup, change to: newWidth = 0
window.onresize = function (){
    newWidth = doc.body.clientWidth;
    if(cWidth != newWidth){
        cWidth = newWidth;
        console.log("clientWidth:", cWidth); //instead of alert(cWidth);
     };
};
  • This is the proper way to detect the duplicate resize event. Either the first or second event will not actually modify the viewport. Perpahs `window.clientWidth/Height` is better than `document.body.clientWidth`. – Halcyon May 19 '15 at 12:52
  • 1
    @Halcyon You are misunderstanding the concept of resize events and/or the asynchonous nature of Javascript. This approach will not solve the issue. – Christoph May 19 '15 at 14:33
0

I propose other solution because I don't like the timeouts,

   `var resized;
    window.onresize = function () {
        if(resized){
            resized = false;
        }
        else{
            resized = true;
            alert('resize');
        }
    };`
josean
  • 1
  • 1
    This assumes there are exactly two events. If there is only one event, or more than two events, this code will inaccurately block events. – Halcyon May 19 '15 at 12:53