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]); | |
arv (Not doing code reviews)
2014/01/09 15:47:15
Doesn't this break sub classing?
function SubProm
rossberg
2014/01/09 16:09:56
I agree, but it's what the spec says.
arv (Not doing code reviews)
2014/01/09 19:13:27
I think this is the right call for now. Once we su
| |
66 if (typeof resolver !== 'function') | |
67 throw MakeTypeError('resolver_not_a_function', [resolver]); | |
65 var promise = PromiseInit(this); | 68 var promise = PromiseInit(this); |
66 resolver(function(x) { PromiseResolve(promise, x) }, | 69 try { |
67 function(r) { PromiseReject(promise, r) }); | 70 resolver(function(x) { PromiseResolve(promise, x) }, |
68 // TODO(rossberg): current draft makes exception from this call asynchronous, | 71 function(r) { PromiseReject(promise, r) }); |
69 // but that's probably a mistake. | 72 } catch (e) { |
73 PromiseReject(promise, e); | |
74 } | |
70 } | 75 } |
71 | 76 |
72 function PromiseSet(promise, status, value, onResolve, onReject) { | 77 function PromiseSet(promise, status, value, onResolve, onReject) { |
73 SET_PRIVATE(promise, promiseStatus, status); | 78 SET_PRIVATE(promise, promiseStatus, status); |
74 SET_PRIVATE(promise, promiseValue, value); | 79 SET_PRIVATE(promise, promiseValue, value); |
75 SET_PRIVATE(promise, promiseOnResolve, onResolve); | 80 SET_PRIVATE(promise, promiseOnResolve, onResolve); |
76 SET_PRIVATE(promise, promiseOnReject, onReject); | 81 SET_PRIVATE(promise, promiseOnReject, onReject); |
77 return promise; | 82 return promise; |
78 } | 83 } |
79 | 84 |
80 function PromiseInit(promise) { | 85 function PromiseInit(promise) { |
81 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray) | 86 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray) |
82 } | 87 } |
83 | 88 |
84 function PromiseDone(promise, status, value, promiseQueue) { | 89 function PromiseDone(promise, status, value, promiseQueue) { |
85 if (GET_PRIVATE(promise, promiseStatus) !== 0) return; | 90 if (GET_PRIVATE(promise, promiseStatus) === 0) { |
86 PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue)); | 91 PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue)); |
87 PromiseSet(promise, status, value); | 92 PromiseSet(promise, status, value); |
93 } | |
88 } | 94 } |
89 | 95 |
90 function PromiseResolve(promise, x) { | 96 function PromiseResolve(promise, x) { |
91 PromiseDone(promise, +1, x, promiseOnResolve) | 97 PromiseDone(promise, +1, x, promiseOnResolve) |
92 } | 98 } |
93 | 99 |
94 function PromiseReject(promise, r) { | 100 function PromiseReject(promise, r) { |
95 PromiseDone(promise, -1, r, promiseOnReject) | 101 PromiseDone(promise, -1, r, promiseOnReject) |
96 } | 102 } |
97 | 103 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
212 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : | 218 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : |
213 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); | 219 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); |
214 }, | 220 }, |
215 onReject | 221 onReject |
216 ); | 222 ); |
217 } | 223 } |
218 | 224 |
219 PromiseCoerce.table = new $WeakMap; | 225 PromiseCoerce.table = new $WeakMap; |
220 | 226 |
221 function PromiseCoerce(constructor, x) { | 227 function PromiseCoerce(constructor, x) { |
222 var then; | 228 if (!(IsPromise(x) || IS_NULL_OR_UNDEFINED(x))) { |
223 if (IsPromise(x)) { | 229 var then = x.then; |
224 return x; | 230 if (typeof then === 'function') { |
225 } else if (!IS_NULL_OR_UNDEFINED(x) && %IsCallable(then = x.then)) { | 231 if (PromiseCoerce.table.has(x)) { |
226 if (PromiseCoerce.table.has(x)) { | 232 return PromiseCoerce.table.get(x); |
227 return PromiseCoerce.table.get(x); | 233 } else { |
228 } else { | 234 var deferred = %_CallFunction(constructor, PromiseDeferred); |
229 var deferred = constructor.deferred(); | 235 PromiseCoerce.table.set(x, deferred.promise); |
230 PromiseCoerce.table.set(x, deferred.promise); | 236 try { |
231 try { | 237 %_CallFunction(x, deferred.resolve, deferred.reject, then); |
232 %_CallFunction(x, deferred.resolve, deferred.reject, then); | 238 } catch(e) { |
233 } catch(e) { | 239 deferred.reject(e); |
234 deferred.reject(e); | 240 } |
241 return deferred.promise; | |
235 } | 242 } |
236 return deferred.promise; | |
237 } | 243 } |
238 } else { | |
239 return x; | |
240 } | 244 } |
245 return x; | |
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); |
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) } |
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) { |
arv (Not doing code reviews)
2014/01/09 15:47:15
Rename this to PromiseRace to match?
Why isn't th
rossberg
2014/01/09 16:09:56
Because the resolve/reject functions at some point
| |
274 var deferred = this.deferred(); | 281 var deferred = %_CallFunction(this, PromiseDeferred); |
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, |
292 "resolved", PromiseResolved, | 302 "resolve", PromiseResolved, |
293 "rejected", PromiseRejected, | 303 "reject", PromiseRejected, |
294 "all", PromiseAll, | 304 "all", PromiseAll, |
295 "one", PromiseOne, | 305 "race", 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, |
arv (Not doing code reviews)
2014/01/09 15:47:15
Any plan to upstream chain into the spec?
rossberg
2014/01/09 16:09:56
Yes, but current stakeholders refuse to consider i
| |
300 "then", PromiseThen, | 310 "then", PromiseThen, |
301 "catch", PromiseCatch | 311 "catch", PromiseCatch |
302 ]); | 312 ]); |
303 } | 313 } |
304 | 314 |
305 SetUpPromise(); | 315 SetUpPromise(); |
OLD | NEW |