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 |