- add sources.
[platform/framework/web/crosswalk.git] / src / ui / webui / resources / js / cr / promise.js
1 // Copyright (c) 2012 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.
4
5 /**
6  * @fileoverview This implementes a future promise class.
7  */
8
9 cr.define('cr', function() {
10
11   /**
12    * Sentinel used to mark a value as pending.
13    * @const
14    */
15   var PENDING_VALUE = {};
16
17   /**
18    * Creates a future promise.
19    * @param {*=} opt_value The value to set the promise to. If set completes
20    *     the promise immediately.
21    * @constructor
22    */
23   function Promise(opt_value) {
24     /**
25      * An array of the callbacks.
26      * @type {!Array.<!Function>}
27      * @private
28      */
29     this.callbacks_ = [];
30
31     if (arguments.length > 0)
32       this.value = opt_value;
33   }
34
35   Promise.prototype = {
36     /**
37      * The current value.
38      * @type {*}
39      * @private
40      */
41     value_: PENDING_VALUE,
42
43     /**
44      * The value of the future promise. Accessing this before the promise has
45      * been fulfilled will throw an error. If this is set to an exception
46      * accessing this will throw as well.
47      * @type {*}
48      */
49     get value() {
50       return this.done ? this.value_ : undefined;
51     },
52     set value(value) {
53       if (!this.done) {
54         this.value_ = value;
55         for (var i = 0; i < this.callbacks_.length; i++) {
56           this.callbacks_[i].call(null, value);
57         }
58         this.callbacks_.length = 0;
59       }
60     },
61
62     /**
63      * Whether the future promise has been fulfilled.
64      * @type {boolean}
65      */
66     get done() {
67       return this.value_ !== PENDING_VALUE;
68     },
69
70     /**
71      * Adds a listener to the future promise. The function will be called when
72      * the promise is fulfilled. If the promise is already fullfilled this will
73      * never call the function.
74      * @param {!Function} fun The function to call.
75      */
76     addListener: function(fun) {
77       if (this.done)
78         fun(this.value);
79       else
80         this.callbacks_.push(fun);
81     },
82
83     /**
84      * Removes a previously added listener from the future promise.
85      * @param {!Function} fun The function to remove.
86      */
87     removeListener: function(fun) {
88       var i = this.callbacks_.indexOf(fun);
89       if (i >= 0)
90         this.callbacks_.splice(i, 1);
91     },
92
93     /**
94      * If the promise is done then this returns the string representation of
95      * the value.
96      * @return {string} The string representation of the promise.
97      * @override
98      */
99     toString: function() {
100       if (this.done)
101         return String(this.value);
102       else
103         return '[object Promise]';
104     },
105
106     /**
107      * Override to allow arithmetic.
108      * @override
109      */
110     valueOf: function() {
111       return this.value;
112     }
113   };
114
115   /**
116    * When a future promise is done call {@code fun}. This also calls the
117    * function if the promise has already been fulfilled.
118    * @param {!Promise} p The promise.
119    * @param {!Function} fun The function to call when the promise is fulfilled.
120    */
121   Promise.when = function(p, fun) {
122     p.addListener(fun);
123   };
124
125   /**
126    * Creates a new promise the will be fulfilled after {@code t} ms.
127    * @param {number} t The time to wait before the promise is fulfilled.
128    * @param {*=} opt_value The value to return after the wait.
129    * @return {!Promise} The new future promise.
130    */
131   Promise.wait = function(t, opt_value) {
132     var p = new Promise;
133     window.setTimeout(function() {
134       p.value = opt_value;
135     }, t);
136     return p;
137   };
138
139   /**
140    * Creates a new future promise that is fulfilled when any of the promises are
141    * fulfilled. The value of the returned promise will be the value of the first
142    * fulfilled promise.
143    * @param {...!Promise} var_args The promises used to build up the new
144    *     promise.
145    * @return {!Promise} The new promise that will be fulfilled when any of the
146    *     passed in promises are fulfilled.
147    */
148   Promise.any = function(var_args) {
149     var p = new Promise;
150     function f(v) {
151       p.value = v;
152     }
153     for (var i = 0; i < arguments.length; i++) {
154       arguments[i].addListener(f);
155     }
156     return p;
157   };
158
159   /**
160    * Creates a new future promise that is fulfilled when all of the promises are
161    * fulfilled. The value of the returned promise is an array of the values of
162    * the promises passed in.
163    * @param {...!Promise} var_args The promises used to build up the new
164    *     promise.
165    * @return {!Promise} The promise that wraps all the promises in the array.
166    */
167   Promise.all = function(var_args) {
168     var p = new Promise;
169     var args = Array.prototype.slice.call(arguments);
170     var count = args.length;
171     if (!count) {
172       p.value = [];
173       return p;
174     }
175
176     function f(v) {
177       count--;
178       if (!count) {
179         p.value = args.map(function(argP) {
180           return argP.value;
181         });
182       }
183     }
184
185     // Do not use count here since count may be decremented in the call to
186     // addListener if the promise is already done.
187     for (var i = 0; i < args.length; i++) {
188       args[i].addListener(f);
189     }
190
191     return p;
192   };
193
194   /**
195    * Wraps an event in a future promise.
196    * @param {!EventTarget} target The object that dispatches the event.
197    * @param {string} type The type of the event.
198    * @param {boolean=} opt_useCapture Whether to listen to the capture phase or
199    *     the bubble phase.
200    * @return {!Promise} The promise that will be fulfilled when the event is
201    *     dispatched.
202    */
203   Promise.event = function(target, type, opt_useCapture) {
204     var p = new Promise;
205     target.addEventListener(type, function(e) {
206       p.value = e;
207     }, opt_useCapture);
208     return p;
209   };
210
211   return {
212     Promise: Promise
213   };
214 });