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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
53 var promiseStatus = NEW_PRIVATE("Promise#status"); | 53 var promiseStatus = NEW_PRIVATE("Promise#status"); |
54 var promiseValue = NEW_PRIVATE("Promise#value"); | 54 var promiseValue = NEW_PRIVATE("Promise#value"); |
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) { |
yhirano
2013/12/09 02:31:36
I'm still not sure.
The spec has not been changed
rossberg
2013/12/10 10:11:15
No, but the spec requires that exceptions from the
yhirano
2013/12/11 04:46:31
Then can you write a comment?
rossberg
2014/01/09 12:51:43
Changed to throw
| |
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 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : | 216 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : |
213 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); | 217 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); |
214 }, | 218 }, |
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 if (!(IsPromise(x) || IS_NULL_OR_UNDEFINED(x))) { |
223 if (IsPromise(x)) { | 227 var then = x.then; |
224 return x; | 228 if (typeof then === 'function') { |
225 } else if (!IS_NULL_OR_UNDEFINED(x) && %IsCallable(then = x.then)) { | 229 if (PromiseCoerce.table.has(x)) { |
226 if (PromiseCoerce.table.has(x)) { | 230 return PromiseCoerce.table.get(x); |
227 return PromiseCoerce.table.get(x); | 231 } else { |
228 } else { | 232 var deferred = %_CallFunction(constructor, PromiseDeferred); |
229 var deferred = constructor.deferred(); | 233 PromiseCoerce.table.set(x, deferred.promise); |
230 PromiseCoerce.table.set(x, deferred.promise); | 234 try { |
231 try { | 235 %_CallFunction(x, deferred.resolve, deferred.reject, then); |
232 %_CallFunction(x, deferred.resolve, deferred.reject, then); | 236 } catch(e) { |
233 } catch(e) { | 237 deferred.reject(e); |
234 deferred.reject(e); | 238 } |
239 return deferred.promise; | |
235 } | 240 } |
236 return deferred.promise; | |
237 } | 241 } |
238 } else { | |
239 return x; | |
240 } | 242 } |
243 return x; | |
241 } | 244 } |
242 | 245 |
243 | 246 |
244 // Combinators. | 247 // Combinators. |
245 | 248 |
246 function PromiseCast(x) { | 249 function PromiseCast(x) { |
247 // TODO(rossberg): cannot do better until we support @@create. | 250 // TODO(rossberg): cannot do better until we support @@create. |
248 return IsPromise(x) ? x : this.resolved(x); | 251 return IsPromise(x) ? x : this.resolve(x); |
249 } | 252 } |
250 | 253 |
251 function PromiseAll(values) { | 254 function PromiseAll(values) { |
252 var deferred = this.deferred(); | 255 var deferred = %_CallFunction(this, PromiseDeferred); |
253 var resolutions = []; | 256 var resolutions = []; |
254 var count = values.length; | 257 try { |
255 if (count === 0) { | 258 var count = values.length; |
256 deferred.resolve(resolutions); | 259 if (count === 0) { |
257 } else { | 260 deferred.resolve(resolutions); |
258 for (var i = 0; i < values.length; ++i) { | 261 } else { |
259 this.cast(values[i]).chain( | 262 for (var i = 0; i < values.length; ++i) { |
260 function(i, x) { | 263 this.cast(values[i]).chain( |
261 resolutions[i] = x; | 264 function(i, x) { |
262 if (--count === 0) deferred.resolve(resolutions); | 265 resolutions[i] = x; |
263 }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once available | 266 if (--count === 0) deferred.resolve(resolutions); |
264 function(r) { | 267 }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once available |
265 if (count > 0) { count = 0; deferred.reject(r) } | 268 function(r) { deferred.reject(r) } |
266 } | 269 ); |
267 ); | 270 } |
268 } | 271 } |
272 } catch (e) { | |
273 deferred.reject(e) | |
269 } | 274 } |
270 return deferred.promise; | 275 return deferred.promise; |
271 } | 276 } |
272 | 277 |
273 function PromiseOne(values) { // a.k.a. race | 278 function PromiseOne(values) { // a.k.a. race |
274 var deferred = this.deferred(); | 279 var deferred = %_CallFunction(this, PromiseDeferred); |
275 var done = false; | 280 try { |
276 for (var i = 0; i < values.length; ++i) { | 281 for (var i = 0; i < values.length; ++i) { |
277 this.cast(values[i]).chain( | 282 this.cast(values[i]).chain( |
278 function(x) { if (!done) { done = true; deferred.resolve(x) } }, | 283 function(x) { deferred.resolve(x) }, |
279 function(r) { if (!done) { done = true; deferred.reject(r) } } | 284 function(r) { deferred.reject(r) } |
280 ); | 285 ); |
286 } | |
287 } catch (e) { | |
288 deferred.reject(e) | |
281 } | 289 } |
282 return deferred.promise; | 290 return deferred.promise; |
283 } | 291 } |
284 | 292 |
285 //------------------------------------------------------------------- | 293 //------------------------------------------------------------------- |
286 | 294 |
287 function SetUpPromise() { | 295 function SetUpPromise() { |
288 %CheckIsBootstrapping() | 296 %CheckIsBootstrapping() |
289 global.Promise = $Promise; | 297 global.Promise = $Promise; |
290 InstallFunctions($Promise, DONT_ENUM, [ | 298 InstallFunctions($Promise, DONT_ENUM, [ |
291 "deferred", PromiseDeferred, | 299 "defer", PromiseDeferred, |
292 "resolved", PromiseResolved, | 300 "resolve", PromiseResolved, |
293 "rejected", PromiseRejected, | 301 "reject", PromiseRejected, |
294 "all", PromiseAll, | 302 "all", PromiseAll, |
295 "one", PromiseOne, | 303 "one", PromiseOne, |
arv (Not doing code reviews)
2013/12/10 14:21:24
This should be race
rossberg
2014/01/09 12:51:43
Done.
| |
296 "cast", PromiseCast | 304 "cast", PromiseCast |
297 ]); | 305 ]); |
298 InstallFunctions($Promise.prototype, DONT_ENUM, [ | 306 InstallFunctions($Promise.prototype, DONT_ENUM, [ |
299 "chain", PromiseChain, | 307 "chain", PromiseChain, |
300 "then", PromiseThen, | 308 "then", PromiseThen, |
301 "catch", PromiseCatch | 309 "catch", PromiseCatch |
302 ]); | 310 ]); |
303 } | 311 } |
304 | 312 |
305 SetUpPromise(); | 313 SetUpPromise(); |
OLD | NEW |