| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 "use strict"; | 5 "use strict"; |
| 6 | 6 |
| 7 // This file relies on the fact that the following declaration has been made | 7 // This file relies on the fact that the following declaration has been made |
| 8 // in runtime.js: | 8 // in runtime.js: |
| 9 // var $Object = global.Object | 9 // var $Object = global.Object |
| 10 // var $WeakMap = global.WeakMap | 10 // var $WeakMap = global.WeakMap |
| 11 | 11 |
| 12 | 12 |
| 13 var $Promise = Promise; | 13 var $Promise = function Promise(resolver) { |
| 14 if (resolver === promiseRaw) return; |
| 15 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); |
| 16 if (!IS_SPEC_FUNCTION(resolver)) |
| 17 throw MakeTypeError('resolver_not_a_function', [resolver]); |
| 18 var promise = PromiseInit(this); |
| 19 try { |
| 20 %DebugPromiseHandlePrologue(function() { return promise }); |
| 21 resolver(function(x) { PromiseResolve(promise, x) }, |
| 22 function(r) { PromiseReject(promise, r) }); |
| 23 } catch (e) { |
| 24 PromiseReject(promise, e); |
| 25 } finally { |
| 26 %DebugPromiseHandleEpilogue(); |
| 27 } |
| 28 } |
| 14 | 29 |
| 15 | 30 |
| 16 //------------------------------------------------------------------- | 31 //------------------------------------------------------------------- |
| 17 | 32 |
| 18 // Core functionality. | 33 // Core functionality. |
| 19 | 34 |
| 20 // Status values: 0 = pending, +1 = resolved, -1 = rejected | 35 // Status values: 0 = pending, +1 = resolved, -1 = rejected |
| 21 var promiseStatus = GLOBAL_PRIVATE("Promise#status"); | 36 var promiseStatus = GLOBAL_PRIVATE("Promise#status"); |
| 22 var promiseValue = GLOBAL_PRIVATE("Promise#value"); | 37 var promiseValue = GLOBAL_PRIVATE("Promise#value"); |
| 23 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve"); | 38 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve"); |
| 24 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject"); | 39 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject"); |
| 25 var promiseRaw = GLOBAL_PRIVATE("Promise#raw"); | 40 var promiseRaw = GLOBAL_PRIVATE("Promise#raw"); |
| 26 | 41 |
| 27 function IsPromise(x) { | 42 function IsPromise(x) { |
| 28 return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus); | 43 return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus); |
| 29 } | 44 } |
| 30 | 45 |
| 31 function Promise(resolver) { | |
| 32 if (resolver === promiseRaw) return; | |
| 33 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); | |
| 34 if (typeof resolver !== 'function') | |
| 35 throw MakeTypeError('resolver_not_a_function', [resolver]); | |
| 36 var promise = PromiseInit(this); | |
| 37 try { | |
| 38 %DebugPromiseHandlePrologue(function() { return promise }); | |
| 39 resolver(function(x) { PromiseResolve(promise, x) }, | |
| 40 function(r) { PromiseReject(promise, r) }); | |
| 41 } catch (e) { | |
| 42 PromiseReject(promise, e); | |
| 43 } finally { | |
| 44 %DebugPromiseHandleEpilogue(); | |
| 45 } | |
| 46 } | |
| 47 | |
| 48 function PromiseSet(promise, status, value, onResolve, onReject) { | 46 function PromiseSet(promise, status, value, onResolve, onReject) { |
| 49 SET_PRIVATE(promise, promiseStatus, status); | 47 SET_PRIVATE(promise, promiseStatus, status); |
| 50 SET_PRIVATE(promise, promiseValue, value); | 48 SET_PRIVATE(promise, promiseValue, value); |
| 51 SET_PRIVATE(promise, promiseOnResolve, onResolve); | 49 SET_PRIVATE(promise, promiseOnResolve, onResolve); |
| 52 SET_PRIVATE(promise, promiseOnReject, onReject); | 50 SET_PRIVATE(promise, promiseOnReject, onReject); |
| 53 return promise; | 51 return promise; |
| 54 } | 52 } |
| 55 | 53 |
| 56 function PromiseInit(promise) { | 54 function PromiseInit(promise) { |
| 57 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray) | 55 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray) |
| (...skipping 13 matching lines...) Expand all Loading... |
| 71 function PromiseReject(promise, r) { | 69 function PromiseReject(promise, r) { |
| 72 PromiseDone(promise, -1, r, promiseOnReject) | 70 PromiseDone(promise, -1, r, promiseOnReject) |
| 73 } | 71 } |
| 74 | 72 |
| 75 | 73 |
| 76 // For API. | 74 // For API. |
| 77 | 75 |
| 78 function PromiseNopResolver() {} | 76 function PromiseNopResolver() {} |
| 79 | 77 |
| 80 function PromiseCreate() { | 78 function PromiseCreate() { |
| 81 return new Promise(PromiseNopResolver) | 79 return new $Promise(PromiseNopResolver) |
| 82 } | 80 } |
| 83 | 81 |
| 84 | 82 |
| 85 // Convenience. | 83 // Convenience. |
| 86 | 84 |
| 87 function PromiseDeferred() { | 85 function PromiseDeferred() { |
| 88 if (this === $Promise) { | 86 if (this === $Promise) { |
| 89 // Optimized case, avoid extra closure. | 87 // Optimized case, avoid extra closure. |
| 90 var promise = PromiseInit(new Promise(promiseRaw)); | 88 var promise = PromiseInit(new $Promise(promiseRaw)); |
| 91 return { | 89 return { |
| 92 promise: promise, | 90 promise: promise, |
| 93 resolve: function(x) { PromiseResolve(promise, x) }, | 91 resolve: function(x) { PromiseResolve(promise, x) }, |
| 94 reject: function(r) { PromiseReject(promise, r) } | 92 reject: function(r) { PromiseReject(promise, r) } |
| 95 }; | 93 }; |
| 96 } else { | 94 } else { |
| 97 var result = {}; | 95 var result = {}; |
| 98 result.promise = new this(function(resolve, reject) { | 96 result.promise = new this(function(resolve, reject) { |
| 99 result.resolve = resolve; | 97 result.resolve = resolve; |
| 100 result.reject = reject; | 98 result.reject = reject; |
| 101 }) | 99 }) |
| 102 return result; | 100 return result; |
| 103 } | 101 } |
| 104 } | 102 } |
| 105 | 103 |
| 106 function PromiseResolved(x) { | 104 function PromiseResolved(x) { |
| 107 if (this === $Promise) { | 105 if (this === $Promise) { |
| 108 // Optimized case, avoid extra closure. | 106 // Optimized case, avoid extra closure. |
| 109 return PromiseSet(new Promise(promiseRaw), +1, x); | 107 return PromiseSet(new $Promise(promiseRaw), +1, x); |
| 110 } else { | 108 } else { |
| 111 return new this(function(resolve, reject) { resolve(x) }); | 109 return new this(function(resolve, reject) { resolve(x) }); |
| 112 } | 110 } |
| 113 } | 111 } |
| 114 | 112 |
| 115 function PromiseRejected(r) { | 113 function PromiseRejected(r) { |
| 116 if (this === $Promise) { | 114 if (this === $Promise) { |
| 117 // Optimized case, avoid extra closure. | 115 // Optimized case, avoid extra closure. |
| 118 return PromiseSet(new Promise(promiseRaw), -1, r); | 116 return PromiseSet(new $Promise(promiseRaw), -1, r); |
| 119 } else { | 117 } else { |
| 120 return new this(function(resolve, reject) { reject(r) }); | 118 return new this(function(resolve, reject) { reject(r) }); |
| 121 } | 119 } |
| 122 } | 120 } |
| 123 | 121 |
| 124 | 122 |
| 125 // Simple chaining. | 123 // Simple chaining. |
| 126 | 124 |
| 127 function PromiseIdResolveHandler(x) { return x } | 125 function PromiseIdResolveHandler(x) { return x } |
| 128 function PromiseIdRejectHandler(r) { throw r } | 126 function PromiseIdRejectHandler(r) { throw r } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 } | 181 } |
| 184 } finally { | 182 } finally { |
| 185 %DebugPromiseHandleEpilogue(); | 183 %DebugPromiseHandleEpilogue(); |
| 186 } | 184 } |
| 187 } | 185 } |
| 188 | 186 |
| 189 | 187 |
| 190 // Multi-unwrapped chaining with thenable coercion. | 188 // Multi-unwrapped chaining with thenable coercion. |
| 191 | 189 |
| 192 function PromiseThen(onResolve, onReject) { | 190 function PromiseThen(onResolve, onReject) { |
| 193 onResolve = | 191 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve : PromiseIdResolveHandler; |
| 194 IS_NULL_OR_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; | 192 onReject = IS_SPEC_FUNCTION(onReject) ? onReject : PromiseIdRejectHandler; |
| 195 onReject = | |
| 196 IS_NULL_OR_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; | |
| 197 var that = this; | 193 var that = this; |
| 198 var constructor = this.constructor; | 194 var constructor = this.constructor; |
| 199 return %_CallFunction( | 195 return %_CallFunction( |
| 200 this, | 196 this, |
| 201 function(x) { | 197 function(x) { |
| 202 x = PromiseCoerce(constructor, x); | 198 x = PromiseCoerce(constructor, x); |
| 203 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : | 199 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : |
| 204 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); | 200 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); |
| 205 }, | 201 }, |
| 206 onReject, | 202 onReject, |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 SetUpPromise(); | 312 SetUpPromise(); |
| 317 | 313 |
| 318 // Functions to expose promise details to the debugger. | 314 // Functions to expose promise details to the debugger. |
| 319 function GetPromiseStatus(promise) { | 315 function GetPromiseStatus(promise) { |
| 320 return GET_PRIVATE(promise, promiseStatus); | 316 return GET_PRIVATE(promise, promiseStatus); |
| 321 } | 317 } |
| 322 | 318 |
| 323 function GetPromiseValue(promise) { | 319 function GetPromiseValue(promise) { |
| 324 return GET_PRIVATE(promise, promiseValue); | 320 return GET_PRIVATE(promise, promiseValue); |
| 325 } | 321 } |
| OLD | NEW |