WordPress.org

Make WordPress Core

Changeset 30293


Ignore:
Timestamp:
11/10/14 01:46:04 (3 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.