Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(475)

Side by Side Diff: chrome/browser/resources/google_now/utility.js

Issue 19967005: Simplifying using tasks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixing upload glitch Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 'use strict'; 5 'use strict';
6 6
7 // TODO(vadimt): Remove alerts. 7 // TODO(vadimt): Remove alerts.
8 8
9 /** 9 /**
10 * @fileoverview Utility objects and functions for Google Now extension. 10 * @fileoverview Utility objects and functions for Google Now extension.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 */ 53 */
54 function buildTaskManager(areConflicting) { 54 function buildTaskManager(areConflicting) {
55 /** 55 /**
56 * Queue of scheduled tasks. The first element, if present, corresponds to the 56 * Queue of scheduled tasks. The first element, if present, corresponds to the
57 * currently running task. 57 * currently running task.
58 * @type {Array.<Object.<string, function(function())>>} 58 * @type {Array.<Object.<string, function(function())>>}
59 */ 59 */
60 var queue = []; 60 var queue = [];
61 61
62 /** 62 /**
63 * Name of the current step of the currently running task if present, 63 * Count of unfinished callbacks of the current task.
64 * otherwise, null. For diagnostics only. 64 * @type {number}
65 * It's set when the task is started and before each asynchronous operation.
66 */ 65 */
67 var stepName = null; 66 var taskPendingCallbackCount = 0;
67
68 /**
69 * Not yet called required callbacks. Includes both task and non-task
70 * callbacks. This is a map from unique callback id to the stack at the moment
71 * when the callback was wrapped. This stack identifies the callback.
72 * Used only for diagnostics.
73 * @type {Object.<number, string>}
74 */
75 var pendingCallbacks = {};
76
77 /**
78 * True if currently executed code is a part of a task.
79 * @type {boolean}
80 */
81 var isInTask = false;
68 82
69 /** 83 /**
70 * Starts the first queued task. 84 * Starts the first queued task.
71 */ 85 */
72 function startFirst() { 86 function startFirst() {
73 verify(queue.length >= 1, 'startFirst: queue is empty'); 87 verify(queue.length >= 1, 'startFirst: queue is empty');
88 verify(!isInTask, 'startFirst: already in task');
89 isInTask = true;
74 90
75 // Start the oldest queued task, but don't remove it from the queue. 91 // Start the oldest queued task, but don't remove it from the queue.
76 verify( 92 verify(
77 stepName == null, 93 taskPendingCallbackCount == 0,
78 'tasks.startFirst: stepName is not null: ' + stepName + 94 'tasks.startFirst: still have pending task callbacks: ' +
79 ', queue = ' + JSON.stringify(queue)); 95 taskPendingCallbackCount +
96 ', queue = ' + JSON.stringify(queue) +
97 ', pendingCallbacks = ' + JSON.stringify(pendingCallbacks));
80 var entry = queue[0]; 98 var entry = queue[0];
81 stepName = entry.name + '-initial';
82 console.log('Starting task ' + entry.name); 99 console.log('Starting task ' + entry.name);
83 entry.task(finish); 100
101 entry.task(function() {}); // TODO(vadimt): Don't pass parameter.
102
103 verify(isInTask, 'startFirst: not in task at exit');
104 isInTask = false;
105 if (taskPendingCallbackCount == 0)
skare_ 2013/07/22 23:09:54 does this need to be kept separate from pendingCal
vadimt 2013/07/22 23:59:59 pendingCallbacks also includes non-task callbacks.
106 finish();
84 } 107 }
85 108
86 /** 109 /**
87 * Checks if a new task can be added to the task queue. 110 * Checks if a new task can be added to the task queue.
88 * @param {string} taskName Name of the new task. 111 * @param {string} taskName Name of the new task.
89 * @return {boolean} Whether the new task can be added. 112 * @return {boolean} Whether the new task can be added.
90 */ 113 */
91 function canQueue(taskName) { 114 function canQueue(taskName) {
92 for (var i = 0; i < queue.length; ++i) { 115 for (var i = 0; i < queue.length; ++i) {
93 if (areConflicting(taskName, queue[i].name)) { 116 if (areConflicting(taskName, queue[i].name)) {
(...skipping 24 matching lines...) Expand all
118 if (queue.length == 1) { 141 if (queue.length == 1) {
119 startFirst(); 142 startFirst();
120 } 143 }
121 } 144 }
122 145
123 /** 146 /**
124 * Completes the current task and starts the next queued task if available. 147 * Completes the current task and starts the next queued task if available.
125 */ 148 */
126 function finish() { 149 function finish() {
127 verify(queue.length >= 1, 150 verify(queue.length >= 1,
128 'tasks.finish: The task queue is empty; step = ' + stepName); 151 'tasks.finish: The task queue is empty');
129 console.log('Finishing task ' + queue[0].name); 152 console.log('Finishing task ' + queue[0].name);
130 queue.shift(); 153 queue.shift();
131 stepName = null;
132 154
133 if (queue.length >= 1) 155 if (queue.length >= 1)
134 startFirst(); 156 startFirst();
135 } 157 }
136 158
137 /**
138 * Associates a name with the current step of the task. Used for diagnostics
139 * only. A task is a chain of asynchronous events; debugSetStepName should be
140 * called before starting any asynchronous operation.
141 * @param {string} step Name of new step.
142 */
143 function debugSetStepName(step) {
144 stepName = step;
145 }
146
147 // Limiting 1 error report per background page load. 159 // Limiting 1 error report per background page load.
148 var errorReported = false; 160 var errorReported = false;
149 161
150 /** 162 /**
151 * Sends an error report to the server. 163 * Sends an error report to the server.
152 * @param {Error} error Error to report. 164 * @param {Error} error Error to report.
153 */ 165 */
154 function sendErrorReport(error) { 166 function sendErrorReport(error) {
155 var filteredStack = error.stack.replace(/.*\n/, '\n'); 167 var filteredStack = error.stack.replace(/.*\n/, '\n');
156 var file; 168 var file;
(...skipping 21 matching lines...) Expand all
178 '&line=' + encodeURIComponent(line) + 190 '&line=' + encodeURIComponent(line) +
179 '&trace=' + encodeURIComponent(filteredStack); 191 '&trace=' + encodeURIComponent(filteredStack);
180 var request = buildServerRequest('jserror'); 192 var request = buildServerRequest('jserror');
181 request.onloadend = function(event) { 193 request.onloadend = function(event) {
182 console.log('sendErrorReport status: ' + request.status); 194 console.log('sendErrorReport status: ' + request.status);
183 }; 195 };
184 request.send(requestParameters); 196 request.send(requestParameters);
185 } 197 }
186 198
187 /** 199 /**
200 * Unique ID of the next callback.
201 * @type {number}
202 */
203 var nextCallbackId = 0;
204
205 /**
188 * Adds error processing to an API callback. 206 * Adds error processing to an API callback.
189 * @param {Function} callback Callback to instrument. 207 * @param {Function} callback Callback to instrument.
208 * @param {boolean=} opt_dontRequire True if the callback is not required to
209 * be invoked.
190 * @return {Function} Instrumented callback. 210 * @return {Function} Instrumented callback.
191 */ 211 */
192 function wrapCallback(callback) { 212 function wrapCallback(callback, opt_dontRequire) {
213 verify(!(opt_dontRequire && isInTask), 'Unrequired callback in a task.');
214 var callbackId = nextCallbackId++;
215 var isTaskCallback = isInTask;
216 if (isInTask)
217 ++taskPendingCallbackCount;
218 if (!opt_dontRequire)
219 pendingCallbacks[callbackId] = new Error().stack;
220
193 return function() { 221 return function() {
194 // This is the wrapper for the callback. 222 // This is the wrapper for the callback.
195 try { 223 try {
196 return callback.apply(null, arguments); 224 if (isTaskCallback) {
225 verify(!isInTask, 'wrapCallback: already in task');
226 isInTask = true;
227 }
228 if (!opt_dontRequire)
229 delete pendingCallbacks[callbackId];
230
231 // Call the original callback.
232 callback.apply(null, arguments);
233
234 if (isTaskCallback) {
235 verify(isInTask, 'wrapCallback: not in task at exit');
236 isInTask = false;
237 if (--taskPendingCallbackCount == 0)
238 finish();
239 }
197 } catch (error) { 240 } catch (error) {
198 var message = 'Uncaught exception:\n' + error.stack; 241 var message = 'Uncaught exception:\n' + error.stack;
199 console.error(message); 242 console.error(message);
200 if (!errorReported) { 243 if (!errorReported) {
201 errorReported = true; 244 errorReported = true;
202 chrome.metricsPrivate.getIsCrashReportingEnabled(function(isEnabled) { 245 chrome.metricsPrivate.getIsCrashReportingEnabled(function(isEnabled) {
203 if (isEnabled) 246 if (isEnabled)
204 sendErrorReport(error); 247 sendErrorReport(error);
205 }); 248 });
206 alert(message); 249 alert(message);
(...skipping 17 matching lines...) Expand all
224 alert('Cannot instrument ' + functionName); 267 alert('Cannot instrument ' + functionName);
225 268
226 namespace[functionName] = function() { 269 namespace[functionName] = function() {
227 // This is the wrapper for the API function. Pass the wrapped callback to 270 // This is the wrapper for the API function. Pass the wrapped callback to
228 // the original function. 271 // the original function.
229 var callback = arguments[callbackParameter]; 272 var callback = arguments[callbackParameter];
230 if (typeof callback != 'function') { 273 if (typeof callback != 'function') {
231 alert('Argument ' + callbackParameter + ' of ' + functionName + 274 alert('Argument ' + callbackParameter + ' of ' + functionName +
232 ' is not a function'); 275 ' is not a function');
233 } 276 }
234 arguments[callbackParameter] = wrapCallback(callback); 277 arguments[callbackParameter] = wrapCallback(
278 callback, functionName == 'addListener');
235 return originalFunction.apply(namespace, arguments); 279 return originalFunction.apply(namespace, arguments);
236 }; 280 };
237 } 281 }
238 282
239 instrumentApiFunction(chrome.alarms.onAlarm, 'addListener', 0); 283 instrumentApiFunction(chrome.alarms.onAlarm, 'addListener', 0);
240 instrumentApiFunction(chrome.runtime.onSuspend, 'addListener', 0); 284 instrumentApiFunction(chrome.runtime.onSuspend, 'addListener', 0);
241 285
242 chrome.runtime.onSuspend.addListener(function() { 286 chrome.runtime.onSuspend.addListener(function() {
287 var stringifiedPendingCallbacks = JSON.stringify(pendingCallbacks);
243 verify( 288 verify(
244 queue.length == 0, 289 queue.length == 0 && stringifiedPendingCallbacks == '{}',
245 'Incomplete task when unloading event page, queue = ' + 290 'Incomplete task or pending callbacks when unloading event page,' +
246 JSON.stringify(queue) + ', step = ' + stepName); 291 ' queue = ' + JSON.stringify(queue) +
247 verify( 292 ', pendingCallbacks = ' + stringifiedPendingCallbacks);
248 stepName == null,
249 'Step name not null when unloading event page, queue = ' +
250 JSON.stringify(queue) + ', step = ' + stepName);
251 }); 293 });
252 294
253 return { 295 return {
254 add: add, 296 add: add,
255 // TODO(vadimt): Replace with instrumenting callbacks. 297 debugSetStepName: function() {}, // TODO(vadimt): remove
skare_ 2013/07/22 23:09:54 nit: 2 spaces between code and comments. Could thi
vadimt 2013/07/22 23:59:59 Removing this now would break code or would requir
256 debugSetStepName: debugSetStepName,
257 instrumentApiFunction: instrumentApiFunction, 298 instrumentApiFunction: instrumentApiFunction,
258 wrapCallback: wrapCallback 299 wrapCallback: wrapCallback
259 }; 300 };
260 } 301 }
261 302
262 var storage = chrome.storage.local; 303 var storage = chrome.storage.local;
263 304
264 /** 305 /**
265 * Builds an object to manage retrying activities with exponential backoff. 306 * Builds an object to manage retrying activities with exponential backoff.
266 * @param {string} name Name of this attempt manager. 307 * @param {string} name Name of this attempt manager.
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
348 if (alarm.name == alarmName) 389 if (alarm.name == alarmName)
349 attempt(); 390 attempt();
350 }); 391 });
351 392
352 return { 393 return {
353 start: start, 394 start: start,
354 planForNext: planForNext, 395 planForNext: planForNext,
355 stop: stop 396 stop: stop
356 }; 397 };
357 } 398 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698