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

Side by Side Diff: src/promise.js

Issue 64223010: Harmony promises (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed Michael's comments 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/objects.cc ('k') | src/runtime.h » ('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 //-------------------------------------------------------------------
41
42 // Core functionality.
43
44 // Event queue format: [(value, [(handler, deferred)*])*]
45 // I.e., a list of value/tasks pairs, where the value is a resolution value or
46 // rejection reason, and the tasks are a respective list of handler/deferred
47 // pairs waiting for notification of this value. Each handler is an onResolve or
48 // onReject function provided to the same call of 'when' that produced the
49 // associated deferred.
50 var promiseEvents = new InternalArray;
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 var promiseRaw = NEW_PRIVATE("Promise#raw");
58
59 function IsPromise(x) {
60 return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus);
61 }
62
63 function Promise(resolver) {
64 if (resolver === promiseRaw) return;
65 var promise = PromiseInit(this);
66 resolver(function(x) { PromiseResolve(promise, x) },
67 function(r) { PromiseReject(promise, r) });
68 }
69
70 function PromiseSet(promise, status, value, onResolve, onReject) {
71 SET_PRIVATE(promise, promiseStatus, status);
72 SET_PRIVATE(promise, promiseValue, value);
73 SET_PRIVATE(promise, promiseOnResolve, onResolve);
74 SET_PRIVATE(promise, promiseOnReject, onReject);
75 return promise;
76 }
77
78 function PromiseInit(promise) {
79 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray)
80 }
81
82 function PromiseDone(promise, status, value, promiseQueue) {
83 if (GET_PRIVATE(promise, promiseStatus) !== 0)
84 throw MakeTypeError('promise_not_pending', [promise]);
85 PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue));
86 PromiseSet(promise, status, value);
87 }
88
89 function PromiseResolve(promise, x) {
90 PromiseDone(promise, +1, x, promiseOnResolve)
91 }
92
93 function PromiseReject(promise, r) {
94 PromiseDone(promise, -1, r, promiseOnReject)
95 }
96
97
98 // Convenience.
99
100 function PromiseDeferred() {
101 if (this === $Promise) {
102 // Optimized case, avoid extra closure.
103 var promise = PromiseInit(new Promise(promiseRaw));
104 return {
105 promise: promise,
106 resolve: function(x) { PromiseResolve(promise, x) },
107 reject: function(r) { PromiseReject(promise, r) }
108 };
109 } else {
110 var result = {};
111 result.promise = new this(function(resolve, reject) {
112 result.resolve = resolve;
113 result.reject = reject;
114 })
115 return result;
116 }
117 }
118
119 function PromiseResolved(x) {
120 if (this === $Promise) {
121 // Optimized case, avoid extra closure.
122 return PromiseSet(new Promise(promiseRaw), +1, x);
123 } else {
124 return new this(function(resolve, reject) { resolve(x) });
125 }
126 }
127
128 function PromiseRejected(r) {
129 if (this === $Promise) {
130 // Optimized case, avoid extra closure.
131 return PromiseSet(new Promise(promiseRaw), -1, r);
132 } else {
133 return new this(function(resolve, reject) { reject(r) });
134 }
135 }
136
137
138 // Simple chaining (a.k.a. flatMap).
139
140 function PromiseNopHandler() {}
141
142 function PromiseWhen(onResolve, onReject) {
143 onResolve = IS_UNDEFINED(onResolve) ? PromiseNopHandler : onResolve;
144 onReject = IS_UNDEFINED(onReject) ? PromiseNopHandler : onReject;
145 var deferred = %_CallFunction(this.constructor, PromiseDeferred);
146 switch (GET_PRIVATE(this, promiseStatus)) {
147 case UNDEFINED:
148 throw MakeTypeError('not_a_promise', [this]);
149 case 0: // Pending
150 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
151 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
152 break;
153 case +1: // Resolved
154 PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onResolve, deferred]);
155 break;
156 case -1: // Rejected
157 PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onReject, deferred]);
158 break;
159 }
160 return deferred.promise;
161 }
162
163 function PromiseCatch(onReject) {
164 return this.when(UNDEFINED, onReject);
165 }
166
167 function PromiseEnqueue(value, tasks) {
168 promiseEvents.push(value, tasks);
169 %SetMicrotasksPending(true);
170 }
171
172 function PromiseMicrotasksRunner() {
173 var events = promiseEvents;
174 if (events.length > 0) {
175 promiseEvents = new InternalArray;
176 for (var i = 0; i < events.length; i += 2) {
177 var value = events[i];
178 var tasks = events[i + 1];
179 for (var j = 0; j < tasks.length; j += 2) {
180 var handler = tasks[j];
181 var deferred = tasks[j + 1];
182 try {
183 var result = handler(value);
184 if (result === deferred.promise)
185 throw MakeTypeError('promise_cyclic', [result]);
186 else if (IsPromise(result))
187 result.when(deferred.resolve, deferred.reject);
188 else
189 deferred.resolve(result);
190 } catch(e) {
191 try { deferred.reject(e) } catch(e) {}
esprehn 2013/11/15 11:23:19 Swallowing exceptions like this is bad for develop
rossberg 2013/11/15 12:56:57 Good point, although we currently do the same for
192 }
193 }
194 }
195 }
196 }
197 RunMicrotasks.runners.push(PromiseMicrotasksRunner);
198
199
200 // Extended functionality for multi-unwrapping chaining and coercive 'then'.
201
202 function PromiseThen(onResolve, onReject) {
203 onResolve = IS_UNDEFINED(onResolve) ? PromiseNopHandler : onResolve;
204 var that = this;
205 var constructor = this.constructor;
206 return this.when(
207 function(x) {
208 x = PromiseCoerce(constructor, x);
209 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) :
210 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x);
211 },
212 onReject
213 );
214 }
215
216 PromiseCoerce.table = new $WeakMap;
217
218 function PromiseCoerce(constructor, x) {
219 if (IsPromise(x)) {
220 return x;
221 } else if (!IS_NULL_OR_UNDEFINED(x) && 'then' in TO_OBJECT_INLINE(x)) {
222 if (PromiseCoerce.table.has(x)) {
223 return PromiseCoerce.table.get(x);
224 } else {
225 var deferred = constructor.deferred();
226 PromiseCoerce.table.set(x, deferred.promise);
227 try {
228 x.then(deferred.resolve, deferred.reject);
229 } catch(e) {
230 deferred.reject(e);
231 }
232 return deferred.promise;
233 }
234 } else {
235 return x;
236 }
237 }
238
239
240 // Combinators.
241
242 function PromiseCast(x) {
243 // TODO(rossberg): cannot do better until we support @@create.
244 return IsPromise(x) ? x : this.resolved(x);
245 }
246
247 function PromiseAll(values) {
248 var deferred = this.deferred();
249 var count = 0;
250 for (var i = 0; i < values.length; ++i) {
251 ++count;
252 this.cast(values[i]).when(
253 function(x) { if (--count === 0) deferred.resolve() },
254 function(r) { if (count > 0) { count = 0; deferred.reject(r) } }
255 );
256 }
257 return deferred.promise;
258 }
259
260 function PromiseOne(values) {
261 var deferred = this.deferred();
262 var done = false;
263 for (var i = 0; i < values.length; ++i) {
264 this.cast(values[i]).when(
265 function(x) { if (!done) { done = true; deferred.resolve(x) } },
266 function(r) { if (!done) { done = true; deferred.reject(r) } }
267 );
268 }
269 return deferred.promise;
270 }
271
272 //-------------------------------------------------------------------
273
274 function SetUpPromise() {
275 %CheckIsBootstrapping()
276 global.Promise = $Promise;
277 InstallFunctions($Promise, DONT_ENUM, [
278 "deferred", PromiseDeferred,
279 "resolved", PromiseResolved,
280 "rejected", PromiseRejected,
281 "all", PromiseAll,
282 "one", PromiseOne,
283 "cast", PromiseCast
284 ]);
285 InstallFunctions($Promise.prototype, DONT_ENUM, [
286 "when", PromiseWhen,
287 "then", PromiseThen,
288 "catch", PromiseCatch
289 ]);
290 }
291
292 SetUpPromise();
OLDNEW
« no previous file with comments | « src/objects.cc ('k') | src/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698