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

Side by Side Diff: src/promise.js

Issue 71713002: Preliminary promise implementation. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 1 month 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 | « src/messages.js ('k') | test/mjsunit/harmony/iteration-semantics.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29 "use strict";
30
31 //This file relies on the fact that the following declaration has been made
32 //in runtime.js:
33 //var $Object = global.Object;
34 //var $WeakMap = global.WeakMap;
35
36
37 var $Promise = Promise;
38
39
40 // TODO(rossberg): A temporary shim for creating microtasks.
41 function Task(task) {
42 var dummy = {}
43 $Object.observe(dummy, task)
44 dummy.dummy = dummy
45 }
46
47
48 //-------------------------------------------------------------------
49
50 // Core functionality.
51
52 // Status values: 0 = pending, +1 = resolved, -1 = rejected
53 var promiseStatus = NEW_PRIVATE("Promise#status");
54 var promiseValue = NEW_PRIVATE("Promise#value");
55 var promiseOnResolve = NEW_PRIVATE("Promise#onResolve");
56 var promiseOnReject = NEW_PRIVATE("Promise#onReject");
57
58 function IsPromise(x) {
59 return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus);
60 }
61
62 function Promise(resolver) {
63 SET_PRIVATE(this, promiseStatus, 0);
64 SET_PRIVATE(this, promiseOnResolve, []);
65 SET_PRIVATE(this, promiseOnReject, []);
66 var that = this;
67 resolver(function(x) { PromiseResolve(that, x) },
68 function(r) { PromiseReject(that, r) });
69 }
70
71 function PromiseResolve(promise, x) {
72 if (GET_PRIVATE(promise, promiseStatus) !== 0)
73 throw MakeTypeError('promise_not_pending', [promise]);
74 PromiseQueue(GET_PRIVATE(promise, promiseOnResolve), x);
75 SET_PRIVATE(promise, promiseValue, x);
76 SET_PRIVATE(promise, promiseOnResolve, UNDEFINED);
77 SET_PRIVATE(promise, promiseOnReject, UNDEFINED);
78 SET_PRIVATE(promise, promiseStatus, +1);
79 }
80
81 function PromiseReject(promise, r) {
82 if (GET_PRIVATE(promise, promiseStatus) !== 0)
83 throw MakeTypeError('promise_not_pending', [promise]);
84 PromiseQueue(GET_PRIVATE(promise, promiseOnReject), r);
85 SET_PRIVATE(promise, promiseValue, r);
86 SET_PRIVATE(promise, promiseOnResolve, UNDEFINED);
87 SET_PRIVATE(promise, promiseOnReject, UNDEFINED);
88 SET_PRIVATE(promise, promiseStatus, -1);
89 }
90
91 function PromiseQueue(tasks, x) {
92 for (var i in tasks) {
93 Task(function() { tasks[i](x) });
94 }
95 }
96
97
98 // Convenience.
99
100 function PromiseDeferred() {
101 var result = {};
102 result.promise = new this(function(resolve, reject) {
103 result.resolve = resolve;
104 result.reject = reject;
105 })
106 return result;
107 }
108
109 function PromiseResolved(x) {
110 return new this(function(resolve, reject) { resolve(x) });
111 }
112
113 function PromiseRejected(r) {
114 return new this(function(resolve, reject) { reject(r) });
115 }
116
117
118 // Simple chaining (a.k.a. flatMap).
119
120 function PromiseNopHandler() {}
121
122 function PromiseWhen(onResolve, onReject) {
123 onResolve = IS_UNDEFINED(onResolve) ? PromiseNopHandler : onResolve;
124 onReject = IS_UNDEFINED(onReject) ? PromiseNopHandler : onReject;
125 var deferred = Promise.deferred.call(this.constructor);
126 switch (GET_PRIVATE(this, promiseStatus)) {
127 case UNDEFINED:
128 throw MakeTypeError('not_a_promise', [this]);
129 case 0: // Pending
130 GET_PRIVATE(this, promiseOnResolve).push(
131 PromiseChain(deferred, onResolve));
132 GET_PRIVATE(this, promiseOnReject).push(
133 PromiseChain(deferred, onReject));
134 break
135 case +1: // Resolved
136 PromiseQueue([PromiseChain(deferred, onResolve)],
137 GET_PRIVATE(this, promiseValue));
138 break
139 case -1: // Rejected
140 PromiseQueue([PromiseChain(deferred, onReject)],
141 GET_PRIVATE(this, promiseValue));
142 break
143 default:
144 unreachable();
145 }
146 return deferred.promise;
147 }
148
149 function PromiseCatch(onReject) {
150 return this.when(UNDEFINED, onReject);
151 }
152
153 // TODO(rossberg): uncurry
154 function PromiseChain(deferred, handler) {
155 return function(x) {
156 try {
157 var y = handler(x);
158 if (y === deferred.promise)
159 throw MakeTypeError('promise_cyclic', [y]);
160 else if (IsPromise(y))
161 y.when(deferred.resolve, deferred.reject);
162 else
163 deferred.resolve(y);
164 } catch(e) {
165 deferred.reject(e);
166 }
167 }
168 }
169
170
171 // Extended functionality for multi-unwrapping chaining and coercive 'then'.
172
173 function PromiseThen(onResolve, onReject) {
174 onResolve = IS_UNDEFINED(onResolve) ? PromiseNopHandler : onResolve
175 var that = this
176 var constructor = this.constructor
177 return this.when(
178 function(x) {
179 x = PromiseCoerce(constructor, x)
180 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) :
181 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x)
182 },
183 onReject
184 )
185 }
186
187 PromiseCoerce.table = new $WeakMap
188
189 function PromiseCoerce(constructor, x) {
190 if (IsPromise(x)) {
191 return x
192 } else if (!IS_NULL_OR_UNDEFINED(x) && 'then' in TO_OBJECT(x)) {
193 if (PromiseCoerce.table.has(x)) {
194 return PromiseCoerce.table.get(x)
195 } else {
196 var deferred = constructor.deferred()
197 PromiseCoerce.table.set(x, deferred.promise)
198 try {
199 x.then(deferred.resolve, deferred.reject)
200 } catch(e) {
201 deferred.reject(e)
202 }
203 return deferred.promise
204 }
205 } else {
206 return x
207 }
208 }
209
210
211 // Combinators.
212
213 function PromiseCast(x) {
214 if (x instanceof this) return x
215 if (IsPromise(x)) {
216 var result = this.deferred()
217 x.when(result.resolve, result.reject)
218 return result.promise
219 }
220 return this.resolved(x)
221 }
222
223 function PromiseAll(values) {
224 var deferred = this.deferred()
225 var count = 0
226 for (var i in values) {
227 ++count
228 this.cast(values[i]).when(
229 function(x) { if (--count === 0) deferred.resolve(undefined) },
230 function(r) { if (count > 0) { count = 0; deferred.reject(r) } }
231 )
232 }
233 return deferred.promise
234 }
235
236 function PromiseOne(values) {
237 var deferred = this.deferred()
238 var done = false
239 for (var i in values) {
240 this.cast(values[i]).when(
241 function(x) { if (!done) { done = true; deferred.resolve(x) } },
242 function(r) { if (!done) { done = true; deferred.reject(r) } }
243 )
244 }
245 return deferred.promise
246 }
247
248 //-------------------------------------------------------------------
249
250 function SetUpPromise() {
251 %CheckIsBootstrapping()
252
253 global.Promise = $Promise;
254
255 InstallFunctions($Promise, DONT_ENUM, [
256 "deferred", PromiseDeferred,
257 "resolved", PromiseResolved,
258 "rejected", PromiseRejected,
259 "all", PromiseAll,
260 "one", PromiseOne,
261 "cast", PromiseCast
262 ])
263
264 InstallFunctions($Promise.prototype, DONT_ENUM, [
265 "when", PromiseWhen,
266 "then", PromiseThen,
267 "catch", PromiseCatch
268 ])
269 }
270
271 SetUpPromise();
OLDNEW
« no previous file with comments | « src/messages.js ('k') | test/mjsunit/harmony/iteration-semantics.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698