1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview Queue of pending requests from an origin.
12 * Represents a queued request. Once given a token, call complete() once the
13 * request is processed (or dropped.)
16 function QueuedRequestToken() {}
18 /** Completes (or cancels) this queued request. */
19 QueuedRequestToken
.prototype.complete = function() {};
22 * @param {!RequestQueue} queue The queue for this request.
23 * @param {function(QueuedRequestToken)} beginCb Called when work may begin on
25 * @param {RequestToken} opt_prev Previous request in the same queue.
26 * @param {RequestToken} opt_next Next request in the same queue.
28 * @implements {QueuedRequestToken}
30 function RequestToken(queue
, beginCb
, opt_prev
, opt_next
) {
31 /** @private {!RequestQueue} */
33 /** @type {function(QueuedRequestToken)} */
34 this.beginCb
= beginCb
;
35 /** @type {RequestToken} */
37 /** @type {RequestToken} */
39 /** @private {boolean} */
40 this.completed_
= false;
43 /** Completes (or cancels) this queued request. */
44 RequestToken
.prototype.complete = function() {
45 if (this.completed_
) {
46 // Either the caller called us more than once, or the timer is firing.
47 // Either way, nothing more to do here.
50 this.completed_
= true;
51 this.queue_
.complete(this);
54 /** @return {boolean} Whether this token has already completed. */
55 RequestToken
.prototype.completed = function() {
56 return this.completed_
;
62 function RequestQueue() {
63 /** @private {RequestToken} */
65 /** @private {RequestToken} */
70 * Inserts this token into the queue.
71 * @param {RequestToken} token Queue token
74 RequestQueue
.prototype.insertToken_ = function(token
) {
75 if (this.head_
=== null) {
79 if (!this.tail_
) throw 'Non-empty list missing tail';
80 this.tail_
.next
= token
;
81 token
.prev
= this.tail_
;
87 * Removes this token from the queue.
88 * @param {RequestToken} token Queue token
91 RequestQueue
.prototype.removeToken_ = function(token
) {
93 token
.next
.prev
= token
.prev
;
96 token
.prev
.next
= token
.next
;
98 if (this.head_
=== token
&& this.tail_
=== token
) {
99 this.head_
= this.tail_
= null;
101 if (this.head_
=== token
) {
102 this.head_
= token
.next
;
103 this.head_
.prev
= null;
105 if (this.tail_
=== token
) {
106 this.tail_
= token
.prev
;
107 this.tail_
.next
= null;
110 token
.prev
= token
.next
= null;
114 * Completes this token's request, and begins the next queued request, if one
116 * @param {RequestToken} token Queue token
118 RequestQueue
.prototype.complete = function(token
) {
119 var next
= token
.next
;
120 this.removeToken_(token
);
126 /** @return {boolean} Whether this queue is empty. */
127 RequestQueue
.prototype.empty = function() {
128 return this.head_
=== null;
132 * Queues this request, and, if it's the first request, begins work on it.
133 * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
135 * @param {Countdown} timer Countdown timer
136 * @return {QueuedRequestToken} A token for the request.
138 RequestQueue
.prototype.queueRequest = function(beginCb
, timer
) {
139 var startNow
= this.empty();
140 var token
= new RequestToken(this, beginCb
);
141 // Clone the timer to set a callback on it, which will ensure complete() is
142 // eventually called, even if the caller never gets around to it.
143 timer
.clone(token
.complete
.bind(token
));
144 this.insertToken_(token
);
146 window
.setTimeout(function() {
147 if (!token
.completed()) {
148 token
.beginCb(token
);
158 function OriginKeyedRequestQueue() {
159 /** @private {Object.<string, !RequestQueue>} */
164 * Queues this request, and, if it's the first request, begins work on it.
165 * @param {string} appId Application Id
166 * @param {string} origin Request origin
167 * @param {function(QueuedRequestToken)} beginCb Called when work begins on this
169 * @param {Countdown} timer Countdown timer
170 * @return {QueuedRequestToken} A token for the request.
172 OriginKeyedRequestQueue
.prototype.queueRequest
=
173 function(appId
, origin
, beginCb
, timer
) {
174 var key
= appId
+ origin
;
175 if (!this.requests_
.hasOwnProperty(key
)) {
176 this.requests_
[key
] = new RequestQueue();
178 var queue
= this.requests_
[key
];
179 return queue
.queueRequest(beginCb
, timer
);