Index: Source/core/dom/Promise.js |
diff --git a/Source/core/dom/Promise.js b/Source/core/dom/Promise.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5c6ee5e496daaa44558f9a754c2e3f543a481aca |
--- /dev/null |
+++ b/Source/core/dom/Promise.js |
@@ -0,0 +1,253 @@ |
+/* |
+ * Copyright (C) 2013 Google Inc. All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions are |
+ * met: |
+ * |
+ * * Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * * Redistributions in binary form must reproduce the above |
+ * copyright notice, this list of conditions and the following disclaimer |
+ * in the documentation and/or other materials provided with the |
+ * distribution. |
+ * * Neither the name of Google Inc. nor the names of its |
+ * contributors may be used to endorse or promote products derived from |
+ * this software without specific prior written permission. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ */ |
+ |
+(function(postTask) { |
+ function append(fulfillCallback, rejectCallback) |
+ { |
+ if (this.associated.state === 'fulfilled') { |
+ postTask(fulfillCallback.bind(undefined, this.associated.result)); |
abarth-chromium
2013/06/14 05:07:08
We need to be careful about calling things like "b
|
+ } else if (this.associated.state === 'rejected') { |
+ postTask(rejectCallback.bind(undefined, this.associated.result)); |
+ } else { |
+ this.associated.fulfillCallbacks.push(fulfillCallback); |
+ this.associated.rejectCallbacks.push(rejectCallback); |
+ } |
+ } |
+ |
+ /** |
+ * Promise.prototype.then API. |
+ * @parameter {Function} fulfillCallback |
+ * @parameter {Function} rejectCallback |
+ */ |
+ function then(fulfillCallback, rejectCallback) |
+ { |
+ var resolver; |
+ var promise = new Promise(function(r) { resolver = r; }); |
+ function fulfillWrapper(value) |
+ { |
+ if (fulfillCallback) { |
+ try { |
+ value = fulfillCallback.call(promise, value); |
+ } catch (e) { |
+ resolver.reject(e, true); |
+ return; |
+ } |
+ } |
+ resolver.resolve(value, true); |
+ } |
+ |
+ function rejectWrapper(value) |
+ { |
+ if (rejectCallback) { |
+ try { |
+ value = rejectCallback.call(promise, value); |
+ } catch (e) { |
+ resolver.reject(e, true); |
+ return; |
+ } |
+ resolver.resolve(value, true); |
+ } |
+ resolver.reject(value, true); |
+ } |
+ |
+ this.append(fulfillWrapper, rejectWrapper); |
+ return promise; |
+ } |
+ |
+ /** |
+ * Promise.prototype.catch API. |
+ * @parameter {Function} rejectCallback |
+ */ |
+ function catch_(rejectCallback) |
+ { |
+ return this.then(undefined, rejectCallback); |
+ } |
+ |
+ // static methods |
+ |
+ /** |
+ * Promise.fulfill API. |
+ * @parameter {?} value the value to be set as the promise result. |
+ */ |
+ function fulfill(value) |
+ { |
+ var resolver; |
+ var promise = new Promise(function(r) { resolver = r; }); |
+ resolver.fulfill(value); |
+ return promise; |
+ } |
+ |
+ /** |
+ * Promise.resolve API. |
+ * @parameter {?} value the value to be set as the promise result. |
+ */ |
+ function resolve(value) |
+ { |
+ var resolver; |
+ var promise = new Promise(function(r) { resolver = r; }); |
+ resolver.resolve(value); |
+ return promise; |
+ } |
+ |
+ /** |
+ * Promise.reject API. |
+ * @parameter {?} value the value to be set as the promise result. |
+ */ |
+ function reject(value) |
+ { |
+ var resolver; |
+ var promise = new Promise(function(r) { resolver = r; }); |
+ resolver.reject(value); |
+ return promise; |
+ } |
+ |
+ /** |
+ * Promise.every API. |
+ * @parameters {...Promise} promises |
+ */ |
+ function every() |
+ { |
+ var promises = Array.prototype.slice.call(arguments, 0); |
abarth-chromium
2013/06/14 05:07:08
Similarly, we don't want to depend on any statics.
|
+ var resolver; |
+ var countdown = promises.length; |
+ var results = []; |
+ var resultPromise = new Promise(function(r) { resolver = r; }); |
+ |
+ if (promises.length === 0) { |
+ resolver.resolve(undefined); |
+ return resultPromise; |
+ } |
+ promises.forEach(function(promise, index) { |
+ if (!(promise instanceof Promise)) { |
+ throw TypeError(); |
+ } |
+ // We use Promise.prototype.then instead of |append| function. |
+ promise.then(function(result) { |
+ results[index] = result; |
+ if (--countdown === 0) { |
+ resolver.resolve(results, true); |
+ } |
+ }, function(result) { |
+ resolver.reject(result, true); |
+ }); |
+ }); |
+ return resultPromise; |
+ } |
+ |
+ /** |
+ * Promise.any API. |
+ * @parameters {...Promise} promises |
+ */ |
+ function any() |
+ { |
+ var promises = Array.prototype.slice.call(arguments, 0); |
+ var resolver; |
+ var results = []; |
+ var resultPromise = new Promise(function(r) { resolver = r; }); |
+ |
+ if (promises.length === 0) { |
+ resolver.resolve(undefined); |
+ return resultPromise; |
+ } |
+ promises.forEach(function(promise) { |
+ if (!(promise instanceof Promise)) { |
+ throw TypeError(); |
+ } |
+ // We use Promise.prototype.then instead of |append| function. |
+ promise.then(function(result) { |
+ resolver.resolve(result, true); |
+ }, function(result) { |
+ resolver.reject(result, true); |
+ }); |
+ }); |
+ return resultPromise; |
+ } |
+ |
+ /** |
+ * Promise.some API. |
+ * @parameters {...Promise} promises |
+ */ |
+ function some() |
+ { |
+ var promises = Array.prototype.slice.call(arguments, 0); |
+ var resolver; |
+ var countdown = promises.length; |
+ var results = []; |
+ var resultPromise = new Promise(function(r) { resolver = r; }); |
+ |
+ if (promises.length === 0) { |
+ resolver.resolve(undefined); |
+ return resultPromise; |
+ } |
+ promises.forEach(function(promise, index) { |
+ if (!(promise instanceof Promise)) { |
+ throw TypeError(); |
+ } |
+ // We use Promise.prototype.then instead of |append| function. |
+ promise.then(function (result) { |
+ resolver.resolve(result, true); |
+ }, function(result) { |
+ results[index] = result; |
+ if (--countdown === 0) { |
+ resolver.reject(results, true); |
+ } |
+ }); |
+ }); |
+ return resultPromise; |
+ } |
+ |
+ /** |
+ * Promise constructor. |
+ * Note that this differs from Promise API. |
+ * Blink bridge fills the gap. |
+ */ |
+ function $Promise(callback) |
+ { |
+ this.associated = { |
+ state: 'pending', |
+ result: undefined, |
+ fulfillCallbacks: [], |
+ rejectCallbacks: [] |
+ }; |
+ } |
+ |
+ $Promise.prototype = { |
+ append: append, |
+ then: then, |
+ 'catch': catch_ |
+ }; |
+ $Promise.fulfill = fulfill; |
+ $Promise.resolve = resolve; |
+ $Promise.reject = reject; |
+ $Promise.every = every; |
+ $Promise.any = any; |
+ $Promise.some = some; |
+ return Object.freeze($Promise); |
abarth-chromium
2013/06/14 05:07:08
Why Object.freeze?
|
+}); |