| 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 // For bootstrapper. |
| 13 | 13 |
| 14 var IsPromise; | 14 var IsPromise; |
| 15 var PromiseCreate; | 15 var PromiseCreate; |
| 16 var PromiseResolve; | 16 var PromiseResolve; |
| 17 var PromiseReject; | 17 var PromiseReject; |
| 18 var PromiseChain; | 18 var PromiseChain; |
| 19 var PromiseCatch; | 19 var PromiseCatch; |
| 20 var PromiseThen; | 20 var PromiseThen; |
| 21 var PromiseHasRejectHandler; |
| 21 | 22 |
| 22 // mirror-debugger.js currently uses builtins.promiseStatus. It would be nice | 23 // mirror-debugger.js currently uses builtins.promiseStatus. It would be nice |
| 23 // if we could move these property names into the closure below. | 24 // if we could move these property names into the closure below. |
| 24 // TODO(jkummerow/rossberg/yangguo): Find a better solution. | 25 // TODO(jkummerow/rossberg/yangguo): Find a better solution. |
| 25 | 26 |
| 26 // Status values: 0 = pending, +1 = resolved, -1 = rejected | 27 // Status values: 0 = pending, +1 = resolved, -1 = rejected |
| 27 var promiseStatus = GLOBAL_PRIVATE("Promise#status"); | 28 var promiseStatus = GLOBAL_PRIVATE("Promise#status"); |
| 28 var promiseValue = GLOBAL_PRIVATE("Promise#value"); | 29 var promiseValue = GLOBAL_PRIVATE("Promise#value"); |
| 29 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve"); | 30 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve"); |
| 30 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject"); | 31 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject"); |
| 31 var promiseRaw = GLOBAL_PRIVATE("Promise#raw"); | 32 var promiseRaw = GLOBAL_PRIVATE("Promise#raw"); |
| 33 var promiseDebug = GLOBAL_PRIVATE("Promise#debug"); |
| 32 var lastMicrotaskId = 0; | 34 var lastMicrotaskId = 0; |
| 33 | 35 |
| 34 (function() { | 36 (function() { |
| 35 | 37 |
| 36 var $Promise = function Promise(resolver) { | 38 var $Promise = function Promise(resolver) { |
| 37 if (resolver === promiseRaw) return; | 39 if (resolver === promiseRaw) return; |
| 38 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); | 40 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); |
| 39 if (!IS_SPEC_FUNCTION(resolver)) | 41 if (!IS_SPEC_FUNCTION(resolver)) |
| 40 throw MakeTypeError('resolver_not_a_function', [resolver]); | 42 throw MakeTypeError('resolver_not_a_function', [resolver]); |
| 41 var promise = PromiseInit(this); | 43 var promise = PromiseInit(this); |
| 42 try { | 44 try { |
| 43 %DebugPromiseHandlePrologue(function() { return promise }); | 45 %DebugPushPromise(promise); |
| 44 resolver(function(x) { PromiseResolve(promise, x) }, | 46 resolver(function(x) { PromiseResolve(promise, x) }, |
| 45 function(r) { PromiseReject(promise, r) }); | 47 function(r) { PromiseReject(promise, r) }); |
| 46 } catch (e) { | 48 } catch (e) { |
| 47 PromiseReject(promise, e); | 49 PromiseReject(promise, e); |
| 48 } finally { | 50 } finally { |
| 49 %DebugPromiseHandleEpilogue(); | 51 %DebugPopPromise(); |
| 50 } | 52 } |
| 51 } | 53 } |
| 52 | 54 |
| 53 // Core functionality. | 55 // Core functionality. |
| 54 | 56 |
| 55 function PromiseSet(promise, status, value, onResolve, onReject) { | 57 function PromiseSet(promise, status, value, onResolve, onReject) { |
| 56 SET_PRIVATE(promise, promiseStatus, status); | 58 SET_PRIVATE(promise, promiseStatus, status); |
| 57 SET_PRIVATE(promise, promiseValue, value); | 59 SET_PRIVATE(promise, promiseValue, value); |
| 58 SET_PRIVATE(promise, promiseOnResolve, onResolve); | 60 SET_PRIVATE(promise, promiseOnResolve, onResolve); |
| 59 SET_PRIVATE(promise, promiseOnReject, onReject); | 61 SET_PRIVATE(promise, promiseOnReject, onReject); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 deferred.reject(r); | 93 deferred.reject(r); |
| 92 } | 94 } |
| 93 return deferred.promise; | 95 return deferred.promise; |
| 94 } | 96 } |
| 95 } | 97 } |
| 96 return x; | 98 return x; |
| 97 } | 99 } |
| 98 | 100 |
| 99 function PromiseHandle(value, handler, deferred) { | 101 function PromiseHandle(value, handler, deferred) { |
| 100 try { | 102 try { |
| 101 %DebugPromiseHandlePrologue( | 103 %DebugPushPromise(deferred.promise); |
| 102 function() { | |
| 103 var queue = GET_PRIVATE(deferred.promise, promiseOnReject); | |
| 104 return (queue && queue.length == 0) ? deferred.promise : UNDEFINED; | |
| 105 }); | |
| 106 var result = handler(value); | 104 var result = handler(value); |
| 107 if (result === deferred.promise) | 105 if (result === deferred.promise) |
| 108 throw MakeTypeError('promise_cyclic', [result]); | 106 throw MakeTypeError('promise_cyclic', [result]); |
| 109 else if (IsPromise(result)) | 107 else if (IsPromise(result)) |
| 110 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain); | 108 %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain); |
| 111 else | 109 else |
| 112 deferred.resolve(result); | 110 deferred.resolve(result); |
| 113 } catch (exception) { | 111 } catch (exception) { |
| 114 try { | 112 try { deferred.reject(exception); } catch (e) { } |
| 115 %DebugPromiseHandlePrologue(function() { return deferred.promise }); | |
| 116 deferred.reject(exception); | |
| 117 } catch (e) { } finally { | |
| 118 %DebugPromiseHandleEpilogue(); | |
| 119 } | |
| 120 } finally { | 113 } finally { |
| 121 %DebugPromiseHandleEpilogue(); | 114 %DebugPopPromise(); |
| 122 } | 115 } |
| 123 } | 116 } |
| 124 | 117 |
| 125 function PromiseEnqueue(value, tasks, status) { | 118 function PromiseEnqueue(value, tasks, status) { |
| 126 var id, name, instrumenting = DEBUG_IS_ACTIVE; | 119 var id, name, instrumenting = DEBUG_IS_ACTIVE; |
| 127 %EnqueueMicrotask(function() { | 120 %EnqueueMicrotask(function() { |
| 128 if (instrumenting) { | 121 if (instrumenting) { |
| 129 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); | 122 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
| 130 } | 123 } |
| 131 for (var i = 0; i < tasks.length; i += 2) { | 124 for (var i = 0; i < tasks.length; i += 2) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 158 | 151 |
| 159 PromiseCreate = function PromiseCreate() { | 152 PromiseCreate = function PromiseCreate() { |
| 160 return new $Promise(PromiseNopResolver) | 153 return new $Promise(PromiseNopResolver) |
| 161 } | 154 } |
| 162 | 155 |
| 163 PromiseResolve = function PromiseResolve(promise, x) { | 156 PromiseResolve = function PromiseResolve(promise, x) { |
| 164 PromiseDone(promise, +1, x, promiseOnResolve) | 157 PromiseDone(promise, +1, x, promiseOnResolve) |
| 165 } | 158 } |
| 166 | 159 |
| 167 PromiseReject = function PromiseReject(promise, r) { | 160 PromiseReject = function PromiseReject(promise, r) { |
| 161 // Check promise status to confirm that this reject has an effect. |
| 162 // Check promiseDebug property to avoid duplicate event. |
| 163 if (DEBUG_IS_ACTIVE && |
| 164 GET_PRIVATE(promise, promiseStatus) == 0 && |
| 165 !HAS_PRIVATE(promise, promiseDebug)) { |
| 166 %DebugPromiseRejectEvent(promise, r); |
| 167 } |
| 168 PromiseDone(promise, -1, r, promiseOnReject) | 168 PromiseDone(promise, -1, r, promiseOnReject) |
| 169 } | 169 } |
| 170 | 170 |
| 171 // Convenience. | 171 // Convenience. |
| 172 | 172 |
| 173 function PromiseDeferred() { | 173 function PromiseDeferred() { |
| 174 if (this === $Promise) { | 174 if (this === $Promise) { |
| 175 // Optimized case, avoid extra closure. | 175 // Optimized case, avoid extra closure. |
| 176 var promise = PromiseInit(new $Promise(promiseRaw)); | 176 var promise = PromiseInit(new $Promise(promiseRaw)); |
| 177 return { | 177 return { |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 function(x) { deferred.resolve(x) }, | 315 function(x) { deferred.resolve(x) }, |
| 316 function(r) { deferred.reject(r) } | 316 function(r) { deferred.reject(r) } |
| 317 ); | 317 ); |
| 318 } | 318 } |
| 319 } catch (e) { | 319 } catch (e) { |
| 320 deferred.reject(e) | 320 deferred.reject(e) |
| 321 } | 321 } |
| 322 return deferred.promise; | 322 return deferred.promise; |
| 323 } | 323 } |
| 324 | 324 |
| 325 |
| 326 // Utility for debugger |
| 327 |
| 328 PromiseHasRejectHandler = function PromiseHasRejectHandler() { |
| 329 // Mark promise as already having triggered a reject event. |
| 330 SET_PRIVATE(this, promiseDebug, true); |
| 331 var queue = GET_PRIVATE(this, promiseOnReject); |
| 332 return !IS_UNDEFINED(queue) && queue.length > 0; |
| 333 }; |
| 334 |
| 325 // ------------------------------------------------------------------- | 335 // ------------------------------------------------------------------- |
| 326 // Install exported functions. | 336 // Install exported functions. |
| 327 | 337 |
| 328 %CheckIsBootstrapping(); | 338 %CheckIsBootstrapping(); |
| 329 %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM); | 339 %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM); |
| 330 InstallFunctions($Promise, DONT_ENUM, [ | 340 InstallFunctions($Promise, DONT_ENUM, [ |
| 331 "defer", PromiseDeferred, | 341 "defer", PromiseDeferred, |
| 332 "accept", PromiseResolved, | 342 "accept", PromiseResolved, |
| 333 "reject", PromiseRejected, | 343 "reject", PromiseRejected, |
| 334 "all", PromiseAll, | 344 "all", PromiseAll, |
| 335 "race", PromiseOne, | 345 "race", PromiseOne, |
| 336 "resolve", PromiseCast | 346 "resolve", PromiseCast |
| 337 ]); | 347 ]); |
| 338 InstallFunctions($Promise.prototype, DONT_ENUM, [ | 348 InstallFunctions($Promise.prototype, DONT_ENUM, [ |
| 339 "chain", PromiseChain, | 349 "chain", PromiseChain, |
| 340 "then", PromiseThen, | 350 "then", PromiseThen, |
| 341 "catch", PromiseCatch | 351 "catch", PromiseCatch |
| 342 ]); | 352 ]); |
| 343 | 353 |
| 344 })(); | 354 })(); |
| OLD | NEW |