-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Request Scheduler #3371
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
Merged
Merged
Request Scheduler #3371
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
/*global define*/ | ||
define([ | ||
'../ThirdParty/Uri', | ||
'../ThirdParty/when', | ||
'./defaultValue', | ||
'./defined', | ||
'./defineProperties', | ||
'./DeveloperError' | ||
], function( | ||
Uri, | ||
when, | ||
defaultValue, | ||
defined, | ||
defineProperties, | ||
DeveloperError) { | ||
"use strict"; | ||
|
||
var activeRequestsByServer = {}; | ||
var activeRequests = 0; | ||
|
||
/** | ||
* Because browsers throttle the number of parallel requests allowed to each server | ||
* and across all servers, this class tracks the number of active requests in progress | ||
* and prioritizes incoming requests. | ||
* | ||
* @exports RequestScheduler | ||
* | ||
* @see {@link http://wiki.commonjs.org/wiki/Promises/A|CommonJS Promises/A} | ||
* | ||
* @private | ||
*/ | ||
var RequestScheduler = function() { | ||
}; | ||
|
||
var pageUri = typeof document !== 'undefined' ? new Uri(document.location.href) : new Uri(); | ||
|
||
/** | ||
* Get the server name from a given url. | ||
* | ||
* @param {String} url The url. | ||
* @returns {String} The server name. | ||
*/ | ||
RequestScheduler.getServer = function(url) { | ||
//>>includeStart('debug', pragmas.debug); | ||
if (!defined(url)) { | ||
throw new DeveloperError('url is required.'); | ||
} | ||
//>>includeEnd('debug'); | ||
|
||
var uri = new Uri(url).resolve(pageUri); | ||
uri.normalize(); | ||
var server = uri.authority; | ||
if (!/:/.test(server)) { | ||
server = server + ':' + (uri.scheme === 'https' ? '443' : '80'); | ||
} | ||
return server; | ||
}; | ||
|
||
/** | ||
* Get the number of available slots for the given server. | ||
* | ||
* @param {String} url The url to check. | ||
* @returns {Number} The number of available slots. | ||
*/ | ||
RequestScheduler.getNumberOfAvailableRequestsByServer = function(url) { | ||
var server = RequestScheduler.getServer(url); | ||
var activeRequestsForServer = defaultValue(activeRequestsByServer[server], 0); | ||
return RequestScheduler.maximumRequestsPerServer - activeRequestsForServer; | ||
}; | ||
|
||
/** | ||
* Get the number of available slots across all servers. | ||
* | ||
* @returns {Number} The number of available slots. | ||
*/ | ||
RequestScheduler.getNumberOfAvailableRequests = function() { | ||
return RequestScheduler.maximumRequests - activeRequests; | ||
}; | ||
|
||
/** | ||
* Checks if there are available slots to make a request. | ||
* It considers the total number of available slots across all servers, and | ||
* if a url is provided, the total number of available slots at the url's server. | ||
* | ||
* @param {String} [url] The url to check. | ||
* @returns {Boolean} Returns true if there are available slots, otherwise false. | ||
*/ | ||
RequestScheduler.hasAvailableRequests = function(url) { | ||
if (activeRequests >= RequestScheduler.maximumRequests) { | ||
return false; | ||
} | ||
|
||
if (defined(url)) { | ||
var server = RequestScheduler.getServer(url); | ||
var activeRequestsForServer = defaultValue(activeRequestsByServer[server], 0); | ||
if (activeRequestsForServer >= RequestScheduler.maximumRequestsPerServer) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
}; | ||
|
||
/** | ||
* A function that will make a request if there are available slots to the server. | ||
* Returns undefined immediately if the request would exceed the maximum, allowing | ||
* the caller to retry later instead of queueing indefinitely under the browser's control. | ||
* | ||
* @param {String} url The URL to request. | ||
* @param {RequestScheduler~RequestFunction} requestFunction The actual function that | ||
* makes the request. | ||
* @returns {Promise.<Object>|undefined} Either undefined, meaning the request would exceed the maximum number of | ||
* parallel requests, or a Promise for the requested data. | ||
* | ||
* @example | ||
* // throttle requests for an image | ||
* var url = 'http://madeupserver.example.com/myImage.png'; | ||
* var requestFunction = function(url) { | ||
* // in this simple example, loadImage could be used directly as requestFunction. | ||
* return Cesium.loadImage(url); | ||
* }; | ||
* var promise = Cesium.RequestScheduler.throttleRequest(url, requestFunction); | ||
* if (!Cesium.defined(promise)) { | ||
* // too many active requests in progress, try again later. | ||
* } else { | ||
* promise.then(function(image) { | ||
* // handle loaded image | ||
* }); | ||
* } | ||
* | ||
*/ | ||
RequestScheduler.throttleRequest = function(url, requestFunction) { | ||
//>>includeStart('debug', pragmas.debug); | ||
if (!defined(url)) { | ||
throw new DeveloperError('url is required.'); | ||
} | ||
|
||
if (!defined(requestFunction)) { | ||
throw new DeveloperError('requestFunction is required.'); | ||
} | ||
//>>includeEnd('debug'); | ||
|
||
if (activeRequests >= RequestScheduler.maximumRequests) { | ||
return undefined; | ||
} | ||
|
||
var server = RequestScheduler.getServer(url); | ||
var activeRequestsForServer = defaultValue(activeRequestsByServer[server], 0); | ||
if (activeRequestsForServer >= RequestScheduler.maximumRequestsPerServer) { | ||
return undefined; | ||
} | ||
|
||
++activeRequests; | ||
activeRequestsByServer[server] = activeRequestsForServer + 1; | ||
|
||
return when(requestFunction(url), function(result) { | ||
--activeRequests; | ||
--activeRequestsByServer[server]; | ||
return result; | ||
}).otherwise(function(error) { | ||
--activeRequests; | ||
--activeRequestsByServer[server]; | ||
return when.reject(error); | ||
}); | ||
}; | ||
|
||
/** | ||
* Specifies the maximum number of requests that can be simultaneously open to a single server. If this value is higher than | ||
* the number of requests per server actually allowed by the web browser, Cesium's ability to prioritize requests will be adversely | ||
* affected. | ||
* @type {Number} | ||
* @default 6 | ||
*/ | ||
RequestScheduler.maximumRequestsPerServer = 6; | ||
|
||
/** | ||
* Specifies the maximum number of requests that can be simultaneously open for all servers. If this value is higher than | ||
* the number of requests actually allowed by the web browser, Cesium's ability to prioritize requests will be adversely | ||
* affected. | ||
* @type {Number} | ||
* @default 10 | ||
*/ | ||
RequestScheduler.maximumRequests = 10; | ||
|
||
return RequestScheduler; | ||
}); |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's mark this
@private
until we know how it is exposed, e.g., 3D Tiles will just use it under the hood, but if a user creates aModel
instance for a glTF asset, they may choose to make the request immediately or put it in the scheduler. At least, I'm pretty sure that is how we will want to do it.