Chromium Code Reviews| 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 |