OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
55 var promiseOnResolve = NEW_PRIVATE("Promise#onResolve"); | 55 var promiseOnResolve = NEW_PRIVATE("Promise#onResolve"); |
56 var promiseOnReject = NEW_PRIVATE("Promise#onReject"); | 56 var promiseOnReject = NEW_PRIVATE("Promise#onReject"); |
57 var promiseRaw = NEW_PRIVATE("Promise#raw"); | 57 var promiseRaw = NEW_PRIVATE("Promise#raw"); |
58 | 58 |
59 function IsPromise(x) { | 59 function IsPromise(x) { |
60 return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus); | 60 return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus); |
61 } | 61 } |
62 | 62 |
63 function Promise(resolver) { | 63 function Promise(resolver) { |
64 if (resolver === promiseRaw) return; | 64 if (resolver === promiseRaw) return; |
65 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); | |
65 var promise = PromiseInit(this); | 66 var promise = PromiseInit(this); |
66 resolver(function(x) { PromiseResolve(promise, x) }, | 67 try { |
67 function(r) { PromiseReject(promise, r) }); | 68 resolver(function(x) { PromiseResolve(promise, x) }, |
68 // TODO(rossberg): current draft makes exception from this call asynchronous, | 69 function(r) { PromiseReject(promise, r) }); |
69 // but that's probably a mistake. | 70 } catch (e) { |
71 PromiseReject(promise, e); | |
72 } | |
70 } | 73 } |
71 | 74 |
72 function PromiseSet(promise, status, value, onResolve, onReject) { | 75 function PromiseSet(promise, status, value, onResolve, onReject) { |
73 SET_PRIVATE(promise, promiseStatus, status); | 76 SET_PRIVATE(promise, promiseStatus, status); |
74 SET_PRIVATE(promise, promiseValue, value); | 77 SET_PRIVATE(promise, promiseValue, value); |
75 SET_PRIVATE(promise, promiseOnResolve, onResolve); | 78 SET_PRIVATE(promise, promiseOnResolve, onResolve); |
76 SET_PRIVATE(promise, promiseOnReject, onReject); | 79 SET_PRIVATE(promise, promiseOnReject, onReject); |
77 return promise; | 80 return promise; |
78 } | 81 } |
79 | 82 |
80 function PromiseInit(promise) { | 83 function PromiseInit(promise) { |
81 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray) | 84 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray) |
82 } | 85 } |
83 | 86 |
84 function PromiseDone(promise, status, value, promiseQueue) { | 87 function PromiseDone(promise, status, value, promiseQueue) { |
85 if (GET_PRIVATE(promise, promiseStatus) !== 0) return; | 88 if (GET_PRIVATE(promise, promiseStatus) === 0) { |
86 PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue)); | 89 PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue)); |
87 PromiseSet(promise, status, value); | 90 PromiseSet(promise, status, value); |
91 } | |
88 } | 92 } |
89 | 93 |
90 function PromiseResolve(promise, x) { | 94 function PromiseResolve(promise, x) { |
91 PromiseDone(promise, +1, x, promiseOnResolve) | 95 PromiseDone(promise, +1, x, promiseOnResolve) |
92 } | 96 } |
93 | 97 |
94 function PromiseReject(promise, r) { | 98 function PromiseReject(promise, r) { |
95 PromiseDone(promise, -1, r, promiseOnReject) | 99 PromiseDone(promise, -1, r, promiseOnReject) |
96 } | 100 } |
97 | 101 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
215 onReject | 219 onReject |
216 ); | 220 ); |
217 } | 221 } |
218 | 222 |
219 PromiseCoerce.table = new $WeakMap; | 223 PromiseCoerce.table = new $WeakMap; |
220 | 224 |
221 function PromiseCoerce(constructor, x) { | 225 function PromiseCoerce(constructor, x) { |
222 var then; | 226 var then; |
223 if (IsPromise(x)) { | 227 if (IsPromise(x)) { |
224 return x; | 228 return x; |
225 } else if (!IS_NULL_OR_UNDEFINED(x) && %IsCallable(then = x.then)) { | 229 } else if (!IS_NULL_OR_UNDEFINED(x) && |
230 typeof (then = x.then) === 'function') { | |
Dmitry Lomov (no reviews)
2013/12/04 09:24:43
Can we not have assignments in conditions? Pretty
rossberg
2013/12/06 11:43:29
Done.
| |
226 if (PromiseCoerce.table.has(x)) { | 231 if (PromiseCoerce.table.has(x)) { |
227 return PromiseCoerce.table.get(x); | 232 return PromiseCoerce.table.get(x); |
228 } else { | 233 } else { |
229 var deferred = constructor.deferred(); | 234 var deferred = %_CallFunction(constructor, PromiseDeferred); |
230 PromiseCoerce.table.set(x, deferred.promise); | 235 PromiseCoerce.table.set(x, deferred.promise); |
231 try { | 236 try { |
232 %_CallFunction(x, deferred.resolve, deferred.reject, then); | 237 %_CallFunction(x, deferred.resolve, deferred.reject, then); |
233 } catch(e) { | 238 } catch(e) { |
234 deferred.reject(e); | 239 deferred.reject(e); |
235 } | 240 } |
236 return deferred.promise; | 241 return deferred.promise; |
237 } | 242 } |
238 } else { | 243 } else { |
239 return x; | 244 return x; |
240 } | 245 } |
241 } | 246 } |
242 | 247 |
243 | 248 |
244 // Combinators. | 249 // Combinators. |
245 | 250 |
246 function PromiseCast(x) { | 251 function PromiseCast(x) { |
247 // TODO(rossberg): cannot do better until we support @@create. | 252 // TODO(rossberg): cannot do better until we support @@create. |
248 return IsPromise(x) ? x : this.resolved(x); | 253 return IsPromise(x) ? x : this.resolve(x); |
249 } | 254 } |
250 | 255 |
251 function PromiseAll(values) { | 256 function PromiseAll(values) { |
252 var deferred = this.deferred(); | 257 var deferred = %_CallFunction(this, PromiseDeferred); |
Dmitry Lomov (no reviews)
2013/12/04 09:24:43
Instead of using %_CallFunction here and above, le
rossberg
2013/12/06 11:43:29
Why? Avoiding extra hoops like that is exactly why
| |
253 var resolutions = []; | 258 var resolutions = []; |
254 var count = values.length; | 259 try { |
255 if (count === 0) { | 260 var count = values.length; |
256 deferred.resolve(resolutions); | 261 if (count === 0) { |
257 } else { | 262 deferred.resolve(resolutions); |
258 for (var i = 0; i < values.length; ++i) { | 263 } else { |
259 this.cast(values[i]).chain( | 264 for (var i = 0; i < values.length; ++i) { |
260 function(i, x) { | 265 this.cast(values[i]).chain( |
261 resolutions[i] = x; | 266 function(i, x) { |
262 if (--count === 0) deferred.resolve(resolutions); | 267 resolutions[i] = x; |
263 }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once available | 268 if (--count === 0) deferred.resolve(resolutions); |
264 function(r) { | 269 }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once available |
265 if (count > 0) { count = 0; deferred.reject(r) } | 270 function(r) { deferred.reject(r) } |
Dmitry Lomov (no reviews)
2013/12/04 09:24:43
Why 'count > 0' condition disappeared here? What i
rossberg
2013/12/06 11:43:29
Reject used to throw on non-pending promises in an
| |
266 } | 271 ); |
267 ); | 272 } |
268 } | 273 } |
274 } catch (e) { | |
275 deferred.reject(e) | |
269 } | 276 } |
270 return deferred.promise; | 277 return deferred.promise; |
271 } | 278 } |
272 | 279 |
273 function PromiseOne(values) { // a.k.a. race | 280 function PromiseOne(values) { // a.k.a. race |
274 var deferred = this.deferred(); | 281 var deferred = %_CallFunction(this, PromiseDeferred); |
Dmitry Lomov (no reviews)
2013/12/04 09:24:43
Ditto re: %_CallFunction
| |
275 var done = false; | 282 try { |
276 for (var i = 0; i < values.length; ++i) { | 283 for (var i = 0; i < values.length; ++i) { |
277 this.cast(values[i]).chain( | 284 this.cast(values[i]).chain( |
278 function(x) { if (!done) { done = true; deferred.resolve(x) } }, | 285 function(x) { deferred.resolve(x) }, |
279 function(r) { if (!done) { done = true; deferred.reject(r) } } | 286 function(r) { deferred.reject(r) } |
280 ); | 287 ); |
288 } | |
289 } catch (e) { | |
290 deferred.reject(e) | |
281 } | 291 } |
282 return deferred.promise; | 292 return deferred.promise; |
283 } | 293 } |
284 | 294 |
285 //------------------------------------------------------------------- | 295 //------------------------------------------------------------------- |
286 | 296 |
287 function SetUpPromise() { | 297 function SetUpPromise() { |
288 %CheckIsBootstrapping() | 298 %CheckIsBootstrapping() |
289 global.Promise = $Promise; | 299 global.Promise = $Promise; |
290 InstallFunctions($Promise, DONT_ENUM, [ | 300 InstallFunctions($Promise, DONT_ENUM, [ |
291 "deferred", PromiseDeferred, | 301 "defer", PromiseDeferred, |
Dmitry Lomov (no reviews)
2013/12/04 09:24:43
So, my understanding is that 'defer' is non-standa
rossberg
2013/12/06 11:43:29
As per off-line discussion, I leave it in for the
| |
292 "resolved", PromiseResolved, | 302 "resolve", PromiseResolved, |
293 "rejected", PromiseRejected, | 303 "reject", PromiseRejected, |
294 "all", PromiseAll, | 304 "all", PromiseAll, |
295 "one", PromiseOne, | 305 "one", PromiseOne, |
296 "cast", PromiseCast | 306 "cast", PromiseCast |
297 ]); | 307 ]); |
298 InstallFunctions($Promise.prototype, DONT_ENUM, [ | 308 InstallFunctions($Promise.prototype, DONT_ENUM, [ |
299 "chain", PromiseChain, | 309 "chain", PromiseChain, |
300 "then", PromiseThen, | 310 "then", PromiseThen, |
301 "catch", PromiseCatch | 311 "catch", PromiseCatch |
302 ]); | 312 ]); |
303 } | 313 } |
304 | 314 |
305 SetUpPromise(); | 315 SetUpPromise(); |
OLD | NEW |