| 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 // For bootstrapper. |
| 12 | 13 |
| 13 var $Promise = function Promise(resolver) { | 14 var IsPromise; |
| 14 if (resolver === promiseRaw) return; | 15 var PromiseCreate; |
| 15 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); | 16 var PromiseResolve; |
| 16 if (!IS_SPEC_FUNCTION(resolver)) | 17 var PromiseReject; |
| 17 throw MakeTypeError('resolver_not_a_function', [resolver]); | 18 var PromiseChain; |
| 18 var promise = PromiseInit(this); | 19 var PromiseCatch; |
| 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 } | |
| 29 | 20 |
| 30 | 21 // mirror-debugger.js currently uses builtins.promiseStatus. It would be nice |
| 31 //------------------------------------------------------------------- | 22 // if we could move these property names into the closure below. |
| 32 | 23 // TODO(jkummerow/rossberg/yangguo): Find a better solution. |
| 33 // Core functionality. | |
| 34 | 24 |
| 35 // Status values: 0 = pending, +1 = resolved, -1 = rejected | 25 // Status values: 0 = pending, +1 = resolved, -1 = rejected |
| 36 var promiseStatus = GLOBAL_PRIVATE("Promise#status"); | 26 var promiseStatus = GLOBAL_PRIVATE("Promise#status"); |
| 37 var promiseValue = GLOBAL_PRIVATE("Promise#value"); | 27 var promiseValue = GLOBAL_PRIVATE("Promise#value"); |
| 38 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve"); | 28 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve"); |
| 39 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject"); | 29 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject"); |
| 40 var promiseRaw = GLOBAL_PRIVATE("Promise#raw"); | 30 var promiseRaw = GLOBAL_PRIVATE("Promise#raw"); |
| 41 | 31 |
| 42 function IsPromise(x) { | 32 (function() { |
| 43 return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus); | 33 |
| 44 } | 34 var $Promise = function Promise(resolver) { |
| 45 | 35 if (resolver === promiseRaw) return; |
| 46 function PromiseSet(promise, status, value, onResolve, onReject) { | 36 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); |
| 47 SET_PRIVATE(promise, promiseStatus, status); | 37 if (!IS_SPEC_FUNCTION(resolver)) |
| 48 SET_PRIVATE(promise, promiseValue, value); | 38 throw MakeTypeError('resolver_not_a_function', [resolver]); |
| 49 SET_PRIVATE(promise, promiseOnResolve, onResolve); | 39 var promise = PromiseInit(this); |
| 50 SET_PRIVATE(promise, promiseOnReject, onReject); | 40 try { |
| 51 return promise; | 41 %DebugPromiseHandlePrologue(function() { return promise }); |
| 52 } | 42 resolver(function(x) { PromiseResolve(promise, x) }, |
| 53 | 43 function(r) { PromiseReject(promise, r) }); |
| 54 function PromiseInit(promise) { | 44 } catch (e) { |
| 55 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, new InternalArray) | 45 PromiseReject(promise, e); |
| 56 } | 46 } finally { |
| 57 | |
| 58 function PromiseDone(promise, status, value, promiseQueue) { | |
| 59 if (GET_PRIVATE(promise, promiseStatus) === 0) { | |
| 60 PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue)); | |
| 61 PromiseSet(promise, status, value); | |
| 62 } | |
| 63 } | |
| 64 | |
| 65 function PromiseResolve(promise, x) { | |
| 66 PromiseDone(promise, +1, x, promiseOnResolve) | |
| 67 } | |
| 68 | |
| 69 function PromiseReject(promise, r) { | |
| 70 PromiseDone(promise, -1, r, promiseOnReject) | |
| 71 } | |
| 72 | |
| 73 | |
| 74 // For API. | |
| 75 | |
| 76 function PromiseNopResolver() {} | |
| 77 | |
| 78 function PromiseCreate() { | |
| 79 return new $Promise(PromiseNopResolver) | |
| 80 } | |
| 81 | |
| 82 | |
| 83 // Convenience. | |
| 84 | |
| 85 function PromiseDeferred() { | |
| 86 if (this === $Promise) { | |
| 87 // Optimized case, avoid extra closure. | |
| 88 var promise = PromiseInit(new $Promise(promiseRaw)); | |
| 89 return { | |
| 90 promise: promise, | |
| 91 resolve: function(x) { PromiseResolve(promise, x) }, | |
| 92 reject: function(r) { PromiseReject(promise, r) } | |
| 93 }; | |
| 94 } else { | |
| 95 var result = {}; | |
| 96 result.promise = new this(function(resolve, reject) { | |
| 97 result.resolve = resolve; | |
| 98 result.reject = reject; | |
| 99 }) | |
| 100 return result; | |
| 101 } | |
| 102 } | |
| 103 | |
| 104 function PromiseResolved(x) { | |
| 105 if (this === $Promise) { | |
| 106 // Optimized case, avoid extra closure. | |
| 107 return PromiseSet(new $Promise(promiseRaw), +1, x); | |
| 108 } else { | |
| 109 return new this(function(resolve, reject) { resolve(x) }); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 function PromiseRejected(r) { | |
| 114 if (this === $Promise) { | |
| 115 // Optimized case, avoid extra closure. | |
| 116 return PromiseSet(new $Promise(promiseRaw), -1, r); | |
| 117 } else { | |
| 118 return new this(function(resolve, reject) { reject(r) }); | |
| 119 } | |
| 120 } | |
| 121 | |
| 122 | |
| 123 // Simple chaining. | |
| 124 | |
| 125 function PromiseIdResolveHandler(x) { return x } | |
| 126 function PromiseIdRejectHandler(r) { throw r } | |
| 127 | |
| 128 function PromiseChain(onResolve, onReject) { // a.k.a. flatMap | |
| 129 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; | |
| 130 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; | |
| 131 var deferred = %_CallFunction(this.constructor, PromiseDeferred); | |
| 132 switch (GET_PRIVATE(this, promiseStatus)) { | |
| 133 case UNDEFINED: | |
| 134 throw MakeTypeError('not_a_promise', [this]); | |
| 135 case 0: // Pending | |
| 136 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred); | |
| 137 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred); | |
| 138 break; | |
| 139 case +1: // Resolved | |
| 140 PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onResolve, deferred]); | |
| 141 break; | |
| 142 case -1: // Rejected | |
| 143 PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onReject, deferred]); | |
| 144 break; | |
| 145 } | |
| 146 return deferred.promise; | |
| 147 } | |
| 148 | |
| 149 function PromiseCatch(onReject) { | |
| 150 return this.then(UNDEFINED, onReject); | |
| 151 } | |
| 152 | |
| 153 function PromiseEnqueue(value, tasks) { | |
| 154 %EnqueueMicrotask(function() { | |
| 155 for (var i = 0; i < tasks.length; i += 2) { | |
| 156 PromiseHandle(value, tasks[i], tasks[i + 1]) | |
| 157 } | |
| 158 }); | |
| 159 } | |
| 160 | |
| 161 function PromiseHandle(value, handler, deferred) { | |
| 162 try { | |
| 163 %DebugPromiseHandlePrologue( | |
| 164 function() { | |
| 165 var queue = GET_PRIVATE(deferred.promise, promiseOnReject); | |
| 166 return (queue && queue.length == 0) ? deferred.promise : UNDEFINED; | |
| 167 }); | |
| 168 var result = handler(value); | |
| 169 if (result === deferred.promise) | |
| 170 throw MakeTypeError('promise_cyclic', [result]); | |
| 171 else if (IsPromise(result)) | |
| 172 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain); | |
| 173 else | |
| 174 deferred.resolve(result); | |
| 175 } catch (exception) { | |
| 176 try { | |
| 177 %DebugPromiseHandlePrologue(function() { return deferred.promise }); | |
| 178 deferred.reject(exception); | |
| 179 } catch (e) { } finally { | |
| 180 %DebugPromiseHandleEpilogue(); | 47 %DebugPromiseHandleEpilogue(); |
| 181 } | 48 } |
| 182 } finally { | 49 } |
| 183 %DebugPromiseHandleEpilogue(); | 50 |
| 184 } | 51 // Core functionality. |
| 185 } | 52 |
| 186 | 53 function PromiseSet(promise, status, value, onResolve, onReject) { |
| 187 | 54 SET_PRIVATE(promise, promiseStatus, status); |
| 188 // Multi-unwrapped chaining with thenable coercion. | 55 SET_PRIVATE(promise, promiseValue, value); |
| 189 | 56 SET_PRIVATE(promise, promiseOnResolve, onResolve); |
| 190 function PromiseThen(onResolve, onReject) { | 57 SET_PRIVATE(promise, promiseOnReject, onReject); |
| 191 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve : PromiseIdResolveHandler; | 58 return promise; |
| 192 onReject = IS_SPEC_FUNCTION(onReject) ? onReject : PromiseIdRejectHandler; | 59 } |
| 193 var that = this; | 60 |
| 194 var constructor = this.constructor; | 61 function PromiseInit(promise) { |
| 195 return %_CallFunction( | 62 return PromiseSet(promise, 0, UNDEFINED, new InternalArray, |
| 196 this, | 63 new InternalArray) |
| 197 function(x) { | 64 } |
| 198 x = PromiseCoerce(constructor, x); | 65 |
| 199 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : | 66 function PromiseDone(promise, status, value, promiseQueue) { |
| 200 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); | 67 if (GET_PRIVATE(promise, promiseStatus) === 0) { |
| 201 }, | 68 PromiseEnqueue(value, GET_PRIVATE(promise, promiseQueue)); |
| 202 onReject, | 69 PromiseSet(promise, status, value); |
| 203 PromiseChain | 70 } |
| 204 ); | 71 } |
| 205 } | 72 |
| 206 | 73 function PromiseCoerce(constructor, x) { |
| 207 function PromiseCoerce(constructor, x) { | 74 if (!IsPromise(x) && IS_SPEC_OBJECT(x)) { |
| 208 if (!IsPromise(x) && IS_SPEC_OBJECT(x)) { | 75 var then; |
| 209 var then; | |
| 210 try { | |
| 211 then = x.then; | |
| 212 } catch(r) { | |
| 213 return %_CallFunction(constructor, r, PromiseRejected); | |
| 214 } | |
| 215 if (IS_SPEC_FUNCTION(then)) { | |
| 216 var deferred = %_CallFunction(constructor, PromiseDeferred); | |
| 217 try { | 76 try { |
| 218 %_CallFunction(x, deferred.resolve, deferred.reject, then); | 77 then = x.then; |
| 219 } catch(r) { | 78 } catch(r) { |
| 220 deferred.reject(r); | 79 return %_CallFunction(constructor, r, PromiseRejected); |
| 221 } | 80 } |
| 81 if (IS_SPEC_FUNCTION(then)) { |
| 82 var deferred = %_CallFunction(constructor, PromiseDeferred); |
| 83 try { |
| 84 %_CallFunction(x, deferred.resolve, deferred.reject, then); |
| 85 } catch(r) { |
| 86 deferred.reject(r); |
| 87 } |
| 88 return deferred.promise; |
| 89 } |
| 90 } |
| 91 return x; |
| 92 } |
| 93 |
| 94 function PromiseHandle(value, handler, deferred) { |
| 95 try { |
| 96 %DebugPromiseHandlePrologue( |
| 97 function() { |
| 98 var queue = GET_PRIVATE(deferred.promise, promiseOnReject); |
| 99 return (queue && queue.length == 0) ? deferred.promise : UNDEFINED; |
| 100 }); |
| 101 var result = handler(value); |
| 102 if (result === deferred.promise) |
| 103 throw MakeTypeError('promise_cyclic', [result]); |
| 104 else if (IsPromise(result)) |
| 105 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain); |
| 106 else |
| 107 deferred.resolve(result); |
| 108 } catch (exception) { |
| 109 try { |
| 110 %DebugPromiseHandlePrologue(function() { return deferred.promise }); |
| 111 deferred.reject(exception); |
| 112 } catch (e) { } finally { |
| 113 %DebugPromiseHandleEpilogue(); |
| 114 } |
| 115 } finally { |
| 116 %DebugPromiseHandleEpilogue(); |
| 117 } |
| 118 } |
| 119 |
| 120 function PromiseEnqueue(value, tasks) { |
| 121 %EnqueueMicrotask(function() { |
| 122 for (var i = 0; i < tasks.length; i += 2) { |
| 123 PromiseHandle(value, tasks[i], tasks[i + 1]) |
| 124 } |
| 125 }); |
| 126 } |
| 127 |
| 128 function PromiseIdResolveHandler(x) { return x } |
| 129 function PromiseIdRejectHandler(r) { throw r } |
| 130 |
| 131 function PromiseNopResolver() {} |
| 132 |
| 133 // ------------------------------------------------------------------- |
| 134 // Define exported functions. |
| 135 |
| 136 // For bootstrapper. |
| 137 |
| 138 IsPromise = function IsPromise(x) { |
| 139 return IS_SPEC_OBJECT(x) && %HasLocalProperty(x, promiseStatus); |
| 140 } |
| 141 |
| 142 PromiseCreate = function PromiseCreate() { |
| 143 return new $Promise(PromiseNopResolver) |
| 144 } |
| 145 |
| 146 PromiseResolve = function PromiseResolve(promise, x) { |
| 147 PromiseDone(promise, +1, x, promiseOnResolve) |
| 148 } |
| 149 |
| 150 PromiseReject = function PromiseReject(promise, r) { |
| 151 PromiseDone(promise, -1, r, promiseOnReject) |
| 152 } |
| 153 |
| 154 // Convenience. |
| 155 |
| 156 function PromiseDeferred() { |
| 157 if (this === $Promise) { |
| 158 // Optimized case, avoid extra closure. |
| 159 var promise = PromiseInit(new $Promise(promiseRaw)); |
| 160 return { |
| 161 promise: promise, |
| 162 resolve: function(x) { PromiseResolve(promise, x) }, |
| 163 reject: function(r) { PromiseReject(promise, r) } |
| 164 }; |
| 165 } else { |
| 166 var result = {}; |
| 167 result.promise = new this(function(resolve, reject) { |
| 168 result.resolve = resolve; |
| 169 result.reject = reject; |
| 170 }) |
| 171 return result; |
| 172 } |
| 173 } |
| 174 |
| 175 function PromiseResolved(x) { |
| 176 if (this === $Promise) { |
| 177 // Optimized case, avoid extra closure. |
| 178 return PromiseSet(new $Promise(promiseRaw), +1, x); |
| 179 } else { |
| 180 return new this(function(resolve, reject) { resolve(x) }); |
| 181 } |
| 182 } |
| 183 |
| 184 function PromiseRejected(r) { |
| 185 if (this === $Promise) { |
| 186 // Optimized case, avoid extra closure. |
| 187 return PromiseSet(new $Promise(promiseRaw), -1, r); |
| 188 } else { |
| 189 return new this(function(resolve, reject) { reject(r) }); |
| 190 } |
| 191 } |
| 192 |
| 193 // Simple chaining. |
| 194 |
| 195 PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a. |
| 196 // flatMap |
| 197 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; |
| 198 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; |
| 199 var deferred = %_CallFunction(this.constructor, PromiseDeferred); |
| 200 switch (GET_PRIVATE(this, promiseStatus)) { |
| 201 case UNDEFINED: |
| 202 throw MakeTypeError('not_a_promise', [this]); |
| 203 case 0: // Pending |
| 204 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred); |
| 205 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred); |
| 206 break; |
| 207 case +1: // Resolved |
| 208 PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onResolve, deferred]); |
| 209 break; |
| 210 case -1: // Rejected |
| 211 PromiseEnqueue(GET_PRIVATE(this, promiseValue), [onReject, deferred]); |
| 212 break; |
| 213 } |
| 214 return deferred.promise; |
| 215 } |
| 216 |
| 217 PromiseCatch = function PromiseCatch(onReject) { |
| 218 return this.then(UNDEFINED, onReject); |
| 219 } |
| 220 |
| 221 // Multi-unwrapped chaining with thenable coercion. |
| 222 |
| 223 function PromiseThen(onResolve, onReject) { |
| 224 onResolve = IS_SPEC_FUNCTION(onResolve) ? onResolve |
| 225 : PromiseIdResolveHandler; |
| 226 onReject = IS_SPEC_FUNCTION(onReject) ? onReject |
| 227 : PromiseIdRejectHandler; |
| 228 var that = this; |
| 229 var constructor = this.constructor; |
| 230 return %_CallFunction( |
| 231 this, |
| 232 function(x) { |
| 233 x = PromiseCoerce(constructor, x); |
| 234 return x === that ? onReject(MakeTypeError('promise_cyclic', [x])) : |
| 235 IsPromise(x) ? x.then(onResolve, onReject) : onResolve(x); |
| 236 }, |
| 237 onReject, |
| 238 PromiseChain |
| 239 ); |
| 240 } |
| 241 |
| 242 // Combinators. |
| 243 |
| 244 function PromiseCast(x) { |
| 245 // TODO(rossberg): cannot do better until we support @@create. |
| 246 return IsPromise(x) ? x : new this(function(resolve) { resolve(x) }); |
| 247 } |
| 248 |
| 249 function PromiseAll(values) { |
| 250 var deferred = %_CallFunction(this, PromiseDeferred); |
| 251 var resolutions = []; |
| 252 if (!%_IsArray(values)) { |
| 253 deferred.reject(MakeTypeError('invalid_argument')); |
| 222 return deferred.promise; | 254 return deferred.promise; |
| 223 } | 255 } |
| 224 } | 256 try { |
| 225 return x; | 257 var count = values.length; |
| 226 } | 258 if (count === 0) { |
| 227 | 259 deferred.resolve(resolutions); |
| 228 | 260 } else { |
| 229 // Combinators. | 261 for (var i = 0; i < values.length; ++i) { |
| 230 | 262 this.resolve(values[i]).then( |
| 231 function PromiseCast(x) { | 263 function(i, x) { |
| 232 // TODO(rossberg): cannot do better until we support @@create. | 264 resolutions[i] = x; |
| 233 return IsPromise(x) ? x : new this(function(resolve) { resolve(x) }); | 265 if (--count === 0) deferred.resolve(resolutions); |
| 234 } | 266 }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once |
| 235 | 267 // available |
| 236 function PromiseAll(values) { | 268 function(r) { deferred.reject(r) } |
| 237 var deferred = %_CallFunction(this, PromiseDeferred); | 269 ); |
| 238 var resolutions = []; | 270 } |
| 239 if (!%_IsArray(values)) { | 271 } |
| 240 deferred.reject(MakeTypeError('invalid_argument')); | 272 } catch (e) { |
| 273 deferred.reject(e) |
| 274 } |
| 241 return deferred.promise; | 275 return deferred.promise; |
| 242 } | 276 } |
| 243 try { | 277 |
| 244 var count = values.length; | 278 function PromiseOne(values) { |
| 245 if (count === 0) { | 279 var deferred = %_CallFunction(this, PromiseDeferred); |
| 246 deferred.resolve(resolutions); | 280 if (!%_IsArray(values)) { |
| 247 } else { | 281 deferred.reject(MakeTypeError('invalid_argument')); |
| 282 return deferred.promise; |
| 283 } |
| 284 try { |
| 248 for (var i = 0; i < values.length; ++i) { | 285 for (var i = 0; i < values.length; ++i) { |
| 249 this.resolve(values[i]).then( | 286 this.resolve(values[i]).then( |
| 250 function(i, x) { | 287 function(x) { deferred.resolve(x) }, |
| 251 resolutions[i] = x; | |
| 252 if (--count === 0) deferred.resolve(resolutions); | |
| 253 }.bind(UNDEFINED, i), // TODO(rossberg): use let loop once available | |
| 254 function(r) { deferred.reject(r) } | 288 function(r) { deferred.reject(r) } |
| 255 ); | 289 ); |
| 256 } | 290 } |
| 257 } | 291 } catch (e) { |
| 258 } catch (e) { | 292 deferred.reject(e) |
| 259 deferred.reject(e) | 293 } |
| 260 } | |
| 261 return deferred.promise; | |
| 262 } | |
| 263 | |
| 264 function PromiseOne(values) { | |
| 265 var deferred = %_CallFunction(this, PromiseDeferred); | |
| 266 if (!%_IsArray(values)) { | |
| 267 deferred.reject(MakeTypeError('invalid_argument')); | |
| 268 return deferred.promise; | 294 return deferred.promise; |
| 269 } | 295 } |
| 270 try { | 296 |
| 271 for (var i = 0; i < values.length; ++i) { | 297 // ------------------------------------------------------------------- |
| 272 this.resolve(values[i]).then( | 298 // Install exported functions. |
| 273 function(x) { deferred.resolve(x) }, | 299 |
| 274 function(r) { deferred.reject(r) } | |
| 275 ); | |
| 276 } | |
| 277 } catch (e) { | |
| 278 deferred.reject(e) | |
| 279 } | |
| 280 return deferred.promise; | |
| 281 } | |
| 282 | |
| 283 //------------------------------------------------------------------- | |
| 284 | |
| 285 function SetUpPromise() { | |
| 286 %CheckIsBootstrapping(); | 300 %CheckIsBootstrapping(); |
| 287 %SetProperty(global, 'Promise', $Promise, DONT_ENUM); | 301 %SetProperty(global, 'Promise', $Promise, DONT_ENUM); |
| 288 InstallFunctions($Promise, DONT_ENUM, [ | 302 InstallFunctions($Promise, DONT_ENUM, [ |
| 289 "defer", PromiseDeferred, | 303 "defer", PromiseDeferred, |
| 290 "accept", PromiseResolved, | 304 "accept", PromiseResolved, |
| 291 "reject", PromiseRejected, | 305 "reject", PromiseRejected, |
| 292 "all", PromiseAll, | 306 "all", PromiseAll, |
| 293 "race", PromiseOne, | 307 "race", PromiseOne, |
| 294 "resolve", PromiseCast | 308 "resolve", PromiseCast |
| 295 ]); | 309 ]); |
| 296 InstallFunctions($Promise.prototype, DONT_ENUM, [ | 310 InstallFunctions($Promise.prototype, DONT_ENUM, [ |
| 297 "chain", PromiseChain, | 311 "chain", PromiseChain, |
| 298 "then", PromiseThen, | 312 "then", PromiseThen, |
| 299 "catch", PromiseCatch | 313 "catch", PromiseCatch |
| 300 ]); | 314 ]); |
| 301 } | |
| 302 | 315 |
| 303 SetUpPromise(); | 316 })(); |
| OLD | NEW |