Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/result/resultutil.js
2868 views
1
// Copyright 2012 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview This file provides primitives and tools (wait, transform,
17
* chain, combine) that make it easier to work with Results. This section
18
* gives an overview of their functionality along with some examples and the
19
* actual definitions have detailed descriptions next to them.
20
*
21
*
22
* NOTE: goog.result is soft deprecated - we expect to replace this and
23
* goog.async.Deferred with a wrapper around W3C Promises:
24
* http://dom.spec.whatwg.org/#promises.
25
*/
26
27
goog.provide('goog.result');
28
29
goog.require('goog.array');
30
goog.require('goog.result.DependentResult');
31
goog.require('goog.result.Result');
32
goog.require('goog.result.SimpleResult');
33
34
35
/**
36
* Returns a successful result containing the provided value.
37
*
38
* Example:
39
* <pre>
40
*
41
* var value = 'some-value';
42
* var result = goog.result.immediateResult(value);
43
* assertEquals(goog.result.Result.State.SUCCESS, result.getState());
44
* assertEquals(value, result.getValue());
45
*
46
* </pre>
47
*
48
* @param {*} value The value of the result.
49
* @return {!goog.result.Result} A Result object that has already been resolved
50
* to the supplied value.
51
*/
52
goog.result.successfulResult = function(value) {
53
var result = new goog.result.SimpleResult();
54
result.setValue(value);
55
return result;
56
};
57
58
59
/**
60
* Returns a failed result with the optional error slug set.
61
*
62
* Example:
63
* <pre>
64
*
65
* var error = new Error('something-failed');
66
* var result = goog.result.failedResult(error);
67
* assertEquals(goog.result.Result.State.ERROR, result.getState());
68
* assertEquals(error, result.getError());
69
*
70
* </pre>
71
*
72
* @param {*=} opt_error The error to which the result should resolve.
73
* @return {!goog.result.Result} A Result object that has already been resolved
74
* to the supplied Error.
75
*/
76
goog.result.failedResult = function(opt_error) {
77
var result = new goog.result.SimpleResult();
78
result.setError(opt_error);
79
return result;
80
};
81
82
83
/**
84
* Returns a canceled result.
85
* The result will be resolved to an error of type CancelError.
86
*
87
* Example:
88
* <pre>
89
*
90
* var result = goog.result.canceledResult();
91
* assertEquals(goog.result.Result.State.ERROR, result.getState());
92
* var error = result.getError();
93
* assertTrue(error instanceof goog.result.Result.CancelError);
94
*
95
* </pre>
96
*
97
* @return {!goog.result.Result} A canceled Result.
98
*/
99
goog.result.canceledResult = function() {
100
var result = new goog.result.SimpleResult();
101
result.cancel();
102
return result;
103
};
104
105
106
/**
107
* Calls the handler on resolution of the result (success or failure).
108
* The handler is passed the result object as the only parameter. The call will
109
* be immediate if the result is no longer pending.
110
*
111
* Example:
112
* <pre>
113
*
114
* var result = xhr.get('testdata/xhr_test_text.data');
115
*
116
* // Wait for the result to be resolved and alert it's state.
117
* goog.result.wait(result, function(result) {
118
* alert('State: ' + result.getState());
119
* });
120
* </pre>
121
*
122
* @param {!goog.result.Result} result The result to install the handlers.
123
* @param {function(this:T, !goog.result.Result)} handler The handler to be
124
* called. The handler is passed the result object as the only parameter.
125
* @param {T=} opt_scope Optional scope for the handler.
126
* @template T
127
*/
128
goog.result.wait = function(result, handler, opt_scope) {
129
result.wait(handler, opt_scope);
130
};
131
132
133
/**
134
* Calls the handler if the result succeeds. The result object is the only
135
* parameter passed to the handler. The call will be immediate if the result
136
* has already succeeded.
137
*
138
* Example:
139
* <pre>
140
*
141
* var result = xhr.get('testdata/xhr_test_text.data');
142
*
143
* // attach a success handler.
144
* goog.result.waitOnSuccess(result, function(resultValue, result) {
145
* var datavalue = result.getvalue();
146
* alert('value: ' + datavalue + ' == ' + resultValue);
147
* });
148
* </pre>
149
*
150
* @param {!goog.result.Result} result The result to install the handlers.
151
* @param {function(this:T, ?, !goog.result.Result)} handler The handler to be
152
* called. The handler is passed the result value and the result as
153
* parameters.
154
* @param {T=} opt_scope Optional scope for the handler.
155
* @template T
156
*/
157
goog.result.waitOnSuccess = function(result, handler, opt_scope) {
158
goog.result.wait(result, function(res) {
159
if (res.getState() == goog.result.Result.State.SUCCESS) {
160
// 'this' refers to opt_scope
161
handler.call(this, res.getValue(), res);
162
}
163
}, opt_scope);
164
};
165
166
167
/**
168
* Calls the handler if the result action errors. The result object is passed as
169
* the only parameter to the handler. The call will be immediate if the result
170
* object has already resolved to an error.
171
*
172
* Example:
173
*
174
* <pre>
175
*
176
* var result = xhr.get('testdata/xhr_test_text.data');
177
*
178
* // Attach a failure handler.
179
* goog.result.waitOnError(result, function(error) {
180
* // Failed asynchronous call!
181
* });
182
* </pre>
183
*
184
* @param {!goog.result.Result} result The result to install the handlers.
185
* @param {function(this:T, ?, !goog.result.Result)} handler The handler to be
186
* called. The handler is passed the error and the result object as
187
* parameters.
188
* @param {T=} opt_scope Optional scope for the handler.
189
* @template T
190
*/
191
goog.result.waitOnError = function(result, handler, opt_scope) {
192
goog.result.wait(result, function(res) {
193
if (res.getState() == goog.result.Result.State.ERROR) {
194
// 'this' refers to opt_scope
195
handler.call(this, res.getError(), res);
196
}
197
}, opt_scope);
198
};
199
200
201
/**
202
* Given a result and a transform function, returns a new result whose value,
203
* on success, will be the value of the given result after having been passed
204
* through the transform function.
205
*
206
* If the given result is an error, the returned result is also an error and the
207
* transform will not be called.
208
*
209
* Example:
210
* <pre>
211
*
212
* var result = xhr.getJson('testdata/xhr_test_json.data');
213
*
214
* // Transform contents of returned data using 'processJson' and create a
215
* // transformed result to use returned JSON.
216
* var transformedResult = goog.result.transform(result, processJson);
217
*
218
* // Attach success and failure handlers to the transformed result.
219
* goog.result.waitOnSuccess(transformedResult, function(resultValue, result) {
220
* var jsonData = resultValue;
221
* assertEquals('ok', jsonData['stat']);
222
* });
223
*
224
* goog.result.waitOnError(transformedResult, function(error) {
225
* // Failed getJson call
226
* });
227
* </pre>
228
*
229
* @param {!goog.result.Result} result The result whose value will be
230
* transformed.
231
* @param {function(?):?} transformer The transformer
232
* function. The return value of this function will become the value of the
233
* returned result.
234
*
235
* @return {!goog.result.DependentResult} A new Result whose eventual value will
236
* be the returned value of the transformer function.
237
*/
238
goog.result.transform = function(result, transformer) {
239
var returnedResult = new goog.result.DependentResultImpl_([result]);
240
241
goog.result.wait(result, function(res) {
242
if (res.getState() == goog.result.Result.State.SUCCESS) {
243
returnedResult.setValue(transformer(res.getValue()));
244
} else {
245
returnedResult.setError(res.getError());
246
}
247
});
248
249
return returnedResult;
250
};
251
252
253
/**
254
* The chain function aids in chaining of asynchronous Results. This provides a
255
* convenience for use cases where asynchronous operations must happen serially
256
* i.e. subsequent asynchronous operations are dependent on data returned by
257
* prior asynchronous operations.
258
*
259
* It accepts a result and an action callback as arguments and returns a
260
* result. The action callback is called when the first result succeeds and is
261
* supposed to return a second result. The returned result is resolved when one
262
* of both of the results resolve (depending on their success or failure.) The
263
* state and value of the returned result in the various cases is documented
264
* below:
265
* <pre>
266
*
267
* First Result State: Second Result State: Returned Result State:
268
* SUCCESS SUCCESS SUCCESS
269
* SUCCESS ERROR ERROR
270
* ERROR Not created ERROR
271
* </pre>
272
*
273
* The value of the returned result, in the case both results succeed, is the
274
* value of the second result (the result returned by the action callback.)
275
*
276
* Example:
277
* <pre>
278
*
279
* var testDataResult = xhr.get('testdata/xhr_test_text.data');
280
*
281
* // Chain this result to perform another asynchronous operation when this
282
* // Result is resolved.
283
* var chainedResult = goog.result.chain(testDataResult,
284
* function(testDataResult) {
285
*
286
* // The result value of testDataResult is the URL for JSON data.
287
* var jsonDataUrl = testDataResult.getValue();
288
*
289
* // Create a new Result object when the original result is resolved.
290
* var jsonResult = xhr.getJson(jsonDataUrl);
291
*
292
* // Return the newly created Result.
293
* return jsonResult;
294
* });
295
*
296
* // The chained result resolves to success when both results resolve to
297
* // success.
298
* goog.result.waitOnSuccess(chainedResult, function(resultValue, result) {
299
*
300
* // At this point, both results have succeeded and we can use the JSON
301
* // data returned by the second asynchronous call.
302
* var jsonData = resultValue;
303
* assertEquals('ok', jsonData['stat']);
304
* });
305
*
306
* // Attach the error handler to be called when either Result fails.
307
* goog.result.waitOnError(chainedResult, function(result) {
308
* alert('chained result failed!');
309
* });
310
* </pre>
311
*
312
* @param {!goog.result.Result} result The result to chain.
313
* @param {function(this:T, !goog.result.Result):!goog.result.Result}
314
* actionCallback The callback called when the result is resolved. This
315
* callback must return a Result.
316
* @param {T=} opt_scope Optional scope for the action callback.
317
* @return {!goog.result.DependentResult} A result that is resolved when both
318
* the given Result and the Result returned by the actionCallback have
319
* resolved.
320
* @template T
321
*/
322
goog.result.chain = function(result, actionCallback, opt_scope) {
323
var dependentResult = new goog.result.DependentResultImpl_([result]);
324
325
// Wait for the first action.
326
goog.result.wait(result, function(result) {
327
if (result.getState() == goog.result.Result.State.SUCCESS) {
328
// The first action succeeded. Chain the contingent action.
329
var contingentResult = actionCallback.call(opt_scope, result);
330
dependentResult.addParentResult(contingentResult);
331
goog.result.wait(contingentResult, function(contingentResult) {
332
333
// The contingent action completed. Set the dependent result based on
334
// the contingent action's outcome.
335
if (contingentResult.getState() == goog.result.Result.State.SUCCESS) {
336
dependentResult.setValue(contingentResult.getValue());
337
} else {
338
dependentResult.setError(contingentResult.getError());
339
}
340
});
341
} else {
342
// First action failed, the dependent result should also fail.
343
dependentResult.setError(result.getError());
344
}
345
});
346
347
return dependentResult;
348
};
349
350
351
/**
352
* Returns a result that waits on all given results to resolve. Once all have
353
* resolved, the returned result will succeed (and never error).
354
*
355
* Example:
356
* <pre>
357
*
358
* var result1 = xhr.get('testdata/xhr_test_text.data');
359
*
360
* // Get a second independent Result.
361
* var result2 = xhr.getJson('testdata/xhr_test_json.data');
362
*
363
* // Create a Result that resolves when both prior results resolve.
364
* var combinedResult = goog.result.combine(result1, result2);
365
*
366
* // Process data after resolution of both results.
367
* goog.result.waitOnSuccess(combinedResult, function(results) {
368
* goog.array.forEach(results, function(result) {
369
* alert(result.getState());
370
* });
371
* });
372
* </pre>
373
*
374
* @param {...!goog.result.Result} var_args The results to wait on.
375
*
376
* @return {!goog.result.DependentResult} A new Result whose eventual value will
377
* be the resolved given Result objects.
378
*/
379
goog.result.combine = function(var_args) {
380
/** @type {!Array<!goog.result.Result>} */
381
var results = goog.array.clone(arguments);
382
var combinedResult = new goog.result.DependentResultImpl_(results);
383
384
var isResolved = function(res) {
385
return res.getState() != goog.result.Result.State.PENDING;
386
};
387
388
var checkResults = function() {
389
if (combinedResult.getState() == goog.result.Result.State.PENDING &&
390
goog.array.every(results, isResolved)) {
391
combinedResult.setValue(results);
392
}
393
};
394
395
goog.array.forEach(
396
results, function(result) { goog.result.wait(result, checkResults); });
397
398
return combinedResult;
399
};
400
401
402
/**
403
* Returns a result that waits on all given results to resolve. Once all have
404
* resolved, the returned result will succeed if and only if all given results
405
* succeeded. Otherwise it will error.
406
*
407
* Example:
408
* <pre>
409
*
410
* var result1 = xhr.get('testdata/xhr_test_text.data');
411
*
412
* // Get a second independent Result.
413
* var result2 = xhr.getJson('testdata/xhr_test_json.data');
414
*
415
* // Create a Result that resolves when both prior results resolve.
416
* var combinedResult = goog.result.combineOnSuccess(result1, result2);
417
*
418
* // Process data after successful resolution of both results.
419
* goog.result.waitOnSuccess(combinedResult, function(results) {
420
* var textData = results[0].getValue();
421
* var jsonData = results[1].getValue();
422
* assertEquals('Just some data.', textData);
423
* assertEquals('ok', jsonData['stat']);
424
* });
425
*
426
* // Handle errors when either or both results failed.
427
* goog.result.waitOnError(combinedResult, function(combined) {
428
* var results = combined.getError();
429
*
430
* if (results[0].getState() == goog.result.Result.State.ERROR) {
431
* alert('result1 failed');
432
* }
433
*
434
* if (results[1].getState() == goog.result.Result.State.ERROR) {
435
* alert('result2 failed');
436
* }
437
* });
438
* </pre>
439
*
440
* @param {...!goog.result.Result} var_args The results to wait on.
441
*
442
* @return {!goog.result.DependentResult} A new Result whose eventual value will
443
* be an array of values of the given Result objects.
444
*/
445
goog.result.combineOnSuccess = function(var_args) {
446
var results = goog.array.clone(arguments);
447
var combinedResult = new goog.result.DependentResultImpl_(results);
448
449
var resolvedSuccessfully = function(res) {
450
return res.getState() == goog.result.Result.State.SUCCESS;
451
};
452
453
goog.result.wait(
454
goog.result.combine.apply(goog.result.combine, results),
455
// The combined result never ERRORs
456
function(res) {
457
var results =
458
/** @type {Array<!goog.result.Result>} */ (res.getValue());
459
if (goog.array.every(results, resolvedSuccessfully)) {
460
combinedResult.setValue(results);
461
} else {
462
combinedResult.setError(results);
463
}
464
});
465
466
return combinedResult;
467
};
468
469
470
/**
471
* Given a DependentResult, cancels the Results it depends on (that is, the
472
* results returned by getParentResults). This function does not recurse,
473
* so e.g. parents of parents are not canceled; only the immediate parents of
474
* the given Result are canceled.
475
*
476
* Example using @see goog.result.combine:
477
* <pre>
478
* var result1 = xhr.get('testdata/xhr_test_text.data');
479
*
480
* // Get a second independent Result.
481
* var result2 = xhr.getJson('testdata/xhr_test_json.data');
482
*
483
* // Create a Result that resolves when both prior results resolve.
484
* var combinedResult = goog.result.combineOnSuccess(result1, result2);
485
*
486
* combinedResult.wait(function() {
487
* if (combinedResult.isCanceled()) {
488
* goog.result.cancelParentResults(combinedResult);
489
* }
490
* });
491
*
492
* // Now, canceling combinedResult will cancel both result1 and result2.
493
* combinedResult.cancel();
494
* </pre>
495
* @param {!goog.result.DependentResult} dependentResult A Result that is
496
* dependent on the values of other Results (for example the Result of a
497
* goog.result.combine, goog.result.chain, or goog.result.transform call).
498
* @return {boolean} True if any results were successfully canceled; otherwise
499
* false.
500
* TODO(user): Implement a recursive version of this that cancels all
501
* ancestor results.
502
*/
503
goog.result.cancelParentResults = function(dependentResult) {
504
var anyCanceled = false;
505
var results = dependentResult.getParentResults();
506
for (var n = 0; n < results.length; n++) {
507
anyCanceled |= results[n].cancel();
508
}
509
return !!anyCanceled;
510
};
511
512
513
514
/**
515
* A DependentResult represents a Result whose eventual value depends on the
516
* value of one or more other Results. For example, the Result returned by
517
* @see goog.result.chain or @see goog.result.combine is dependent on the
518
* Results given as arguments.
519
*
520
* @param {!Array<!goog.result.Result>} parentResults A list of Results that
521
* will affect the eventual value of this Result.
522
* @constructor
523
* @implements {goog.result.DependentResult}
524
* @extends {goog.result.SimpleResult}
525
* @private
526
*/
527
goog.result.DependentResultImpl_ = function(parentResults) {
528
goog.result.DependentResultImpl_.base(this, 'constructor');
529
/**
530
* A list of Results that will affect the eventual value of this Result.
531
* @type {!Array<!goog.result.Result>}
532
* @private
533
*/
534
this.parentResults_ = parentResults;
535
};
536
goog.inherits(goog.result.DependentResultImpl_, goog.result.SimpleResult);
537
538
539
/**
540
* Adds a Result to the list of Results that affect this one.
541
* @param {!goog.result.Result} parentResult A result whose value affects the
542
* value of this Result.
543
*/
544
goog.result.DependentResultImpl_.prototype.addParentResult = function(
545
parentResult) {
546
this.parentResults_.push(parentResult);
547
};
548
549
550
/** @override */
551
goog.result.DependentResultImpl_.prototype.getParentResults = function() {
552
return this.parentResults_;
553
};
554
555