admin管理员组

文章数量:1323734

In an angularJS app there is quite a big of latency between the user and the server (also bandwidth may be limited), so when the user requests a new page, it has to wait about 2-500ms for it to load.

I'm thinking of "preloading" model data, templates, scripts in the background, but intend to do so ONLY if there is no page requested by the user. If the user requests one specific page I'd like to stop the preloading process and load the resources explicitly requested by the user.

So my question boils down to:

  • Is there a way to make an ajax request "ONLY IF" there is no network activity?
  • Is there a way to "pause" currently running ajax requests? or
  • Is there a way to prioritize ajax requests?

Thanks,

In an angularJS app there is quite a big of latency between the user and the server (also bandwidth may be limited), so when the user requests a new page, it has to wait about 2-500ms for it to load.

I'm thinking of "preloading" model data, templates, scripts in the background, but intend to do so ONLY if there is no page requested by the user. If the user requests one specific page I'd like to stop the preloading process and load the resources explicitly requested by the user.

So my question boils down to:

  • Is there a way to make an ajax request "ONLY IF" there is no network activity?
  • Is there a way to "pause" currently running ajax requests? or
  • Is there a way to prioritize ajax requests?

Thanks,

Share Improve this question asked Nov 5, 2015 at 11:30 Ákos Vandra-MeyerÁkos Vandra-Meyer 2,1751 gold badge25 silver badges46 bronze badges 1
  • can't you use the javascript's setTimeOut()? this would run an ajax request after an specified time. if there are user-triggered request, you just have to reset the timer using the clearTimeout(). – kapitan Commented Oct 4, 2024 at 6:02
Add a ment  | 

5 Answers 5

Reset to default 1

You have multiple types of network activity:

  • XMLHttpRequest,fetch,window.image load are major activity of your concern.
  • There is currently no function to detect overall if there is activity, you have to code for each such activity.

Below is js code(i believe you can implement this in which ever js library you use)

// Monitor XMLHttpRequest
(function(open) {
  XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
    this.addEventListener('loadstart', function() {
      console.log('Network activity started: ', method, url);
      setIdleStatus(false);
    });
    this.addEventListener('loadend', function() {
      console.log('Network activity ended: ', method, url);
      setIdleStatus(true);
    });
    open.call(this, method, url, async, user, pass);
  };
})(XMLHttpRequest.prototype.open);

// Monitor fetch API
(function(fetch) {
  window.fetch = function() {
    console.log('Network activity started with fetch:', arguments);
    setIdleStatus(false);
    return fetch.apply(this, arguments).then(function(response) {
      console.log('Network activity ended with fetch:', response);
      setIdleStatus(true);
      return response;
    });
  };
})(window.fetch);

// Monitor Image loading
(function(originalImage) {
  window.Image = function(width, height) {
    const img = new originalImage(width, height);
    img.addEventListener('load', function() {
      console.log('Image loaded: ', img.src);
      setIdleStatus(true);
    });
    img.addEventListener('error', function() {
      console.log('Image loading error: ', img.src);
      setIdleStatus(true);
    });
    console.log('Image loading started: ', img.src);
    setIdleStatus(false);
    return img;
  };
  // Copy properties from original Image constructor to the new one
  for (let key in originalImage) {
    if (originalImage.hasOwnProperty(key)) {
      window.Image[key] = originalImage[key];
    }
  }
})(window.Image);

// Idle status handling
let idleTimeout;
function setIdleStatus(isIdle) {
  clearTimeout(idleTimeout);
  if (isIdle) {
    idleTimeout = setTimeout(() => {
      console.log('Idle');
    }, 1000); // Adjust the timeout duration as needed
  }
}

If you need fast demo, go to image tab in google search of something, paste the code in console, as soon as the page loads, see it detect stuff and log

As far as I know there is no way to prioritize or pause ajax requests. Now regarding first quesion, here is some idea:

  1. You may have 2 types of requests: normal requests and preloading requests.
  2. Preloading requests start only if there are no normal requests. If any normal request starts all current preloaing requests are cancelled.
  3. Normal requests runs normally.

All this u can implement using interceptors and $http.get(..., {timeout}). You can include img requests using directives into this logic as well.

Disclaimer: such questions sound very akward in 2024. What is size of your app? Is it minified? Cant you just bundle it in 2 js files so u never need to preload any scripts or templates?

I never worked with Angular but here is a proposed logical solution: Hook into the angular router's $routeChangeStart and assign true in a global state (not sure how you do this in angular). Do the opposite in $routeChangeSuccess. You should be able to access global state in your AJAX requests (or pass them from ponent to a function doing the request).

You can use AbortController if you are using fetch() API to cancel in-progress requests.

Prioritizing AJAX requests are not possible natively (as of my knowledge on October 10, 2024) but you can develop your solution, simply create a wrapper function for all your AJAX requests, add a parameter priority with ie. 3 values low | medium | high with a default value (perhaps low) and store them globally (or as a const array of objects having reference to the request object and a priority value). How you're gonna use these priorities is up to you.

For other resources (links, stylesheet, scripts) you should have a look at https://web.dev/articles/preload-critical-assets

You can follow the below code in ajax:

  • use httpInterceptor to keep track of active requests.
  • PreloaderService to manage the preloading process and checks if the network is idle before starting preloading.
  • here the MainCtrl controller stops preloading when a new user request is made for page.
app.factory('httpInterceptor', function($q) {
    var activeRequests = 0;
    return {
        request: function(config) {
            activeRequests++;
            return config;
        },
        response: function(response) {
            activeRequests--;
            return response;
        },
        responseError: function(rejection) {
            activeRequests--;
            return $q.reject(rejection);
        },
        isIdle: function() {
            return activeRequests === 0;
        }
    };
});

app.config(function($httpProvider) {
    $httpProvider.interceptors.push('httpInterceptor');
});

app.service('PreloaderService', function($http, httpInterceptor) {
    var preloading = false;

    this.startPreloading = function() {
        if (httpInterceptor.isIdle()) {
            preloading = true;
            // Start preloading data
            $http.get('/api/preload-data').finally(function() {
                preloading = false;
            });
        }
    };

    this.stopPreloading = function() {
        preloading = false; // Stop preloading when not idle
    };
});

app.controller('MainCtrl', function($scope, PreloaderService) {
    $scope.loadPage = function() {
        PreloaderService.stopPreloading();
        // Load the requested page
        $http.get('/api/load-page').then(function(response) {
            $scope.pageData = response.data;
        });
    };

    $scope.$on('$routeChangeStart', function() {
        PreloaderService.stopPreloading();// Stop preloading on route change
    });

    // Start preloading when the app initializes
    PreloaderService.startPreloading();
});

After words:

  • In AngularJS, there is no built-in way to pause an AJAX request once it has started. However, you can cancel an ongoing request using the timeout property of the $http service.
  • You can implement custom logic queue for prioritizing request, as there is no inbuilt method to do so.

Sounds like requestidlecallback is what you're looking for. There's also a package built on top that exposes an event you can listen to: https://github./choojs/on-idle

本文标签: javascriptCan I detect if a browser39s network activity is idleStack Overflow