Make WordPress Core

Changeset 30293


Ignore:
Timestamp:
11/10/2014 01:46:04 AM (10 years ago)
Author:
azaozz
Message:

Heartbeat:

  • Use the page visibility API (when available) and document.hasFocus() instead of window.onfocus/onblur. Improves speeding up/slowing down the interval and works for iframes by default.
  • Add a setting for minimal interval. Maximum value is 10 min. This overrides all other intervals and cannot be changed after setting it at initialization. Can be used to reduce the frequency of requests on hosts that have low limits for used CPU time, etc.
  • Extend the setting of interval to support 120 sec. (60 sec, is still the default).
  • Always suspend after one hour of keyboard/mouse/touch inactivity.

Fixes #29779.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/js/heartbeat.js

    r29479 r30293  
    5858                originalInterval: 0,
    5959
     60                // Used to limit the number of AJAX requests.
     61                minimalInterval: 0,
     62
    6063                // Used together with tempInterval
    6164                countdown: 0,
     
    8285                userActivityEvents: false,
    8386
    84                 // References to various timeouts
    85                 beatTimer: 0,
    86                 winBlurTimer: 0,
    87                 frameBlurTimer: 0
     87                checkFocusTimer: 0,
     88                beatTimer: 0
    8889            };
    8990
     
    9697         */
    9798        function initialize() {
     99            var options, hidden, visibilityState, visibilitychange;
     100
    98101            if ( typeof window.pagenow === 'string' ) {
    99102                settings.screenId = window.pagenow;
     
    106109            // Pull in options passed from PHP
    107110            if ( typeof window.heartbeatSettings === 'object' ) {
    108                 var options = window.heartbeatSettings;
     111                options = window.heartbeatSettings;
    109112
    110113                // The XHR URL can be passed as option when window.ajaxurl is not set
     
    113116                }
    114117
    115                 // The interval can be from 15 to 60 sec. and can be set temporarily to 5 sec.
     118                // The interval can be from 15 to 120 sec. and can be set temporarily to 5 sec.
     119                // It can be set in the initial options or changed later from JS and/or from PHP.
    116120                if ( options.interval ) {
    117121                    settings.mainInterval = options.interval;
     
    119123                    if ( settings.mainInterval < 15 ) {
    120124                        settings.mainInterval = 15;
    121                     } else if ( settings.mainInterval > 60 ) {
    122                         settings.mainInterval = 60;
     125                    } else if ( settings.mainInterval > 120 ) {
     126                        settings.mainInterval = 120;
    123127                    }
     128                }
     129
     130                // Used to limit the number of AJAX requests. Overrides all other intervals if they are shorter.
     131                // Needed for some hosts that cannot handle frequent requests and the user may exceed the allocated server CPU time, etc.
     132                // The minimal interval can be up to 600 sec. however setting it to longer than 120 sec. will limit or disable
     133                // some of the functionality (like post locks).
     134                // Once set at initialization, minimalInterval cannot be changed/overriden.
     135                if ( options.minimalInterval ) {
     136                    options.minimalInterval = parseInt( options.minimalInterval, 10 );
     137                    settings.minimalInterval = options.minimalInterval > 0 && options.minimalInterval <= 600 ? options.minimalInterval * 1000 : 0;
     138                }
     139
     140                if ( settings.minimalInterval && settings.mainInterval < settings.minimalInterval ) {
     141                    settings.mainInterval = settings.minimalInterval;
    124142                }
    125143
     
    138156            settings.originalInterval = settings.mainInterval;
    139157
    140             // Set focus/blur events on the window
    141             $(window).on( 'blur.wp-heartbeat-focus', function() {
    142                 setFrameFocusEvents();
    143                 // We don't know why the 'blur' was fired. Either the user clicked in an iframe or outside the browser.
    144                 // Running blurred() after some timeout lets us cancel it if the user clicked in an iframe.
    145                 settings.winBlurTimer = window.setTimeout( function(){ blurred(); }, 500 );
    146             }).on( 'focus.wp-heartbeat-focus', function() {
    147                 removeFrameFocusEvents();
    148                 focused();
    149             }).on( 'unload.wp-heartbeat', function() {
     158            // Switch the interval to 120 sec. by using the Page Visibility API.
     159            // If the browser doesn't support it (Safari < 7, Android < 4.4, IE < 10), the interval
     160            // will be increased to 120 sec. after 5 min. of mouse and keyboard inactivity.
     161            if ( typeof document.hidden !== 'undefined' ) {
     162                hidden = 'hidden';
     163                visibilitychange = 'visibilitychange';
     164                visibilityState = 'visibilityState';
     165            } else if ( typeof document.msHidden !== 'undefined' ) { // IE10
     166                hidden = 'msHidden';
     167                visibilitychange = 'msvisibilitychange';
     168                visibilityState = 'msVisibilityState';
     169            } else if ( typeof document.webkitHidden !== 'undefined' ) { // Android
     170                hidden = 'webkitHidden';
     171                visibilitychange = 'webkitvisibilitychange';
     172                visibilityState = 'webkitVisibilityState';
     173            }
     174
     175            if ( hidden ) {
     176                if ( document[hidden] ) {
     177                    settings.hasFocus = false;
     178                }
     179
     180                $document.on( visibilitychange + '.wp-heartbeat', function() {
     181                    if ( document[visibilityState] === 'hidden' ) {
     182                        blurred();
     183                        window.clearInterval( settings.checkFocusTimer );
     184                    } else {
     185                        focused();
     186                        if ( document.hasFocus ) {
     187                            settings.checkFocusTimer = window.setInterval( checkFocus, 10000 );
     188                        }
     189                    }
     190                });
     191            }
     192
     193            // Use document.hasFocus() if available.
     194            if ( document.hasFocus ) {
     195                settings.checkFocusTimer = window.setInterval( checkFocus, 10000 );
     196            }
     197
     198            $(window).on( 'unload.wp-heartbeat', function() {
    150199                // Don't connect any more
    151200                settings.suspend = true;
     
    158207
    159208            // Check for user activity every 30 seconds.
    160             window.setInterval( function(){ checkUserActivity(); }, 30000 );
     209            window.setInterval( checkUserActivity, 30000 );
    161210
    162211            // Start one tick after DOM ready
     
    205254
    206255            return false;
     256        }
     257
     258        /**
     259         * Check if the document's focus has changed
     260         *
     261         * @access private
     262         *
     263         * @return void
     264         */
     265        function checkFocus() {
     266            if ( settings.hasFocus && ! document.hasFocus() ) {
     267                blurred();
     268            } else if ( ! settings.hasFocus && document.hasFocus() ) {
     269                focused();
     270            }
    207271        }
    208272
     
    375439            }
    376440
     441            if ( settings.minimalInterval && interval < settings.minimalInterval ) {
     442                interval = settings.minimalInterval;
     443            }
     444
    377445            window.clearTimeout( settings.beatTimer );
    378446
     
    380448                settings.beatTimer = window.setTimeout(
    381449                    function() {
    382                             connect();
     450                        connect();
    383451                    },
    384452                    interval - delta
     
    390458
    391459        /**
    392          * Set the internal state when the browser window looses focus
     460         * Set the internal state when the browser window becomes hidden or loses focus
    393461         *
    394462         * @access private
     
    397465         */
    398466        function blurred() {
    399             clearFocusTimers();
    400467            settings.hasFocus = false;
    401468        }
    402469
    403470        /**
    404          * Set the internal state when the browser window is focused
     471         * Set the internal state when the browser window becomes visible or is in focus
    405472         *
    406473         * @access private
     
    409476         */
    410477        function focused() {
    411             clearFocusTimers();
    412478            settings.userActivity = time();
    413479
     
    422488
    423489        /**
    424          * Add focus/blur events to all local iframes
    425          *
    426          * Used to detect when focus is moved from the main window to an iframe
    427          *
    428          * @access private
    429          *
    430          * @return void
    431          */
    432         function setFrameFocusEvents() {
    433             $('iframe').each( function( i, frame ) {
    434                 if ( ! isLocalFrame( frame ) ) {
    435                     return;
    436                 }
    437 
    438                 if ( $.data( frame, 'wp-heartbeat-focus' ) ) {
    439                     return;
    440                 }
    441 
    442                 $.data( frame, 'wp-heartbeat-focus', 1 );
    443 
    444                 $( frame.contentWindow ).on( 'focus.wp-heartbeat-focus', function() {
    445                     focused();
    446                 }).on('blur.wp-heartbeat-focus', function() {
    447                     setFrameFocusEvents();
    448                     // We don't know why 'blur' was fired. Either the user clicked in the main window or outside the browser.
    449                     // Running blurred() after some timeout lets us cancel it if the user clicked in the main window.
    450                     settings.frameBlurTimer = window.setTimeout( function(){ blurred(); }, 500 );
    451                 });
    452             });
    453         }
    454 
    455         /**
    456          * Remove the focus/blur events to all local iframes
    457          *
    458          * @access private
    459          *
    460          * @return void
    461          */
    462         function removeFrameFocusEvents() {
    463             $('iframe').each( function( i, frame ) {
    464                 if ( ! isLocalFrame( frame ) ) {
    465                     return;
    466                 }
    467 
    468                 $.removeData( frame, 'wp-heartbeat-focus' );
    469                 $( frame.contentWindow ).off( '.wp-heartbeat-focus' );
    470             });
    471         }
    472 
    473         /**
    474          * Clear the reset timers for focus/blur events on the window and iframes
    475          *
    476          * @access private
    477          *
    478          * @return void
    479          */
    480         function clearFocusTimers() {
    481             window.clearTimeout( settings.winBlurTimer );
    482             window.clearTimeout( settings.frameBlurTimer );
    483         }
    484 
    485         /**
    486490         * Runs when the user becomes active after a period of inactivity
    487491         *
     
    495499
    496500            $('iframe').each( function( i, frame ) {
    497                 if ( ! isLocalFrame( frame ) ) {
    498                     return;
    499                 }
    500 
    501                 $( frame.contentWindow ).off( '.wp-heartbeat-active' );
     501                if ( isLocalFrame( frame ) ) {
     502                    $( frame.contentWindow ).off( '.wp-heartbeat-active' );
     503                }
    502504            });
    503505
     
    520522            var lastActive = settings.userActivity ? time() - settings.userActivity : 0;
    521523
     524            // Throttle down when no mouse or keyboard activity for 5 min.
    522525            if ( lastActive > 300000 && settings.hasFocus ) {
    523                 // Throttle down when no mouse or keyboard activity for 5 min
    524526                blurred();
    525527            }
    526528
    527             if ( settings.suspendEnabled && lastActive > 1200000 ) {
    528                 // Suspend after 20 min. of inactivity
     529            // Suspend after 10 min. of inactivity when suspending is enabled.
     530            // Always suspend after 60 min. of inactivity. This will release the post lock, etc.
     531            if ( ( settings.suspendEnabled && lastActive > 600000 ) || lastActive > 3600000 ) {
    529532                settings.suspend = true;
    530533            }
    531534
    532535            if ( ! settings.userActivityEvents ) {
    533                 $document.on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } );
     536                $document.on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active touchend.wp-heartbeat-active', function() {
     537                    userIsActive();
     538                });
    534539
    535540                $('iframe').each( function( i, frame ) {
    536                     if ( ! isLocalFrame( frame ) ) {
    537                         return;
     541                    if ( isLocalFrame( frame ) ) {
     542                        $( frame.contentWindow ).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active touchend.wp-heartbeat-active', function() {
     543                            userIsActive();
     544                        });
    538545                    }
    539 
    540                     $( frame.contentWindow ).on( 'mouseover.wp-heartbeat-active keyup.wp-heartbeat-active', function(){ userIsActive(); } );
    541546                });
    542547
     
    598603         * If the window doesn't have focus, the interval slows down to 2 min.
    599604         *
    600          * @param mixed speed Interval: 'fast' or 5, 15, 30, 60
     605         * @param mixed speed Interval: 'fast' or 5, 15, 30, 60, 120
    601606         * @param string ticks Used with speed = 'fast' or 5, how many ticks before the interval reverts back
    602607         * @return int Current interval in seconds
     
    621626                        newInterval = 60000;
    622627                        break;
     628                    case 120:
     629                        newInterval = 120000;
     630                        break;
    623631                    case 'long-polling':
    624632                        // Allow long polling, (experimental)
     
    627635                    default:
    628636                        newInterval = settings.originalInterval;
     637                }
     638
     639                if ( settings.minimalInterval && newInterval < settings.minimalInterval ) {
     640                    newInterval = settings.minimalInterval;
    629641                }
    630642
Note: See TracChangeset for help on using the changeset viewer.