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 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 |