Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: src/promise.js

Issue 600723005: Introduce PromiseRejectCallback. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: not omit callback for Promise.reject() Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 var PromiseHasRejectHandler;
22 var PromiseHasUserDefinedRejectHandler;
22 23
23 // mirror-debugger.js currently uses builtins.promiseStatus. It would be nice 24 // mirror-debugger.js currently uses builtins.promiseStatus. It would be nice
24 // if we could move these property names into the closure below. 25 // if we could move these property names into the closure below.
25 // TODO(jkummerow/rossberg/yangguo): Find a better solution. 26 // TODO(jkummerow/rossberg/yangguo): Find a better solution.
26 27
27 // Status values: 0 = pending, +1 = resolved, -1 = rejected 28 // Status values: 0 = pending, +1 = resolved, -1 = rejected
28 var promiseStatus = GLOBAL_PRIVATE("Promise#status"); 29 var promiseStatus = GLOBAL_PRIVATE("Promise#status");
29 var promiseValue = GLOBAL_PRIVATE("Promise#value"); 30 var promiseValue = GLOBAL_PRIVATE("Promise#value");
30 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve"); 31 var promiseOnResolve = GLOBAL_PRIVATE("Promise#onResolve");
31 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject"); 32 var promiseOnReject = GLOBAL_PRIVATE("Promise#onReject");
32 var promiseRaw = GLOBAL_PRIVATE("Promise#raw"); 33 var promiseRaw = GLOBAL_PRIVATE("Promise#raw");
33 var promiseDebug = GLOBAL_PRIVATE("Promise#debug"); 34 var promiseHasHandler = %PromiseHasHandlerSymbol();
34 var lastMicrotaskId = 0; 35 var lastMicrotaskId = 0;
35 36
37
36 (function() { 38 (function() {
37 39
38 var $Promise = function Promise(resolver) { 40 var $Promise = function Promise(resolver) {
39 if (resolver === promiseRaw) return; 41 if (resolver === promiseRaw) return;
40 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]); 42 if (!%_IsConstructCall()) throw MakeTypeError('not_a_promise', [this]);
41 if (!IS_SPEC_FUNCTION(resolver)) 43 if (!IS_SPEC_FUNCTION(resolver))
42 throw MakeTypeError('resolver_not_a_function', [resolver]); 44 throw MakeTypeError('resolver_not_a_function', [resolver]);
43 var promise = PromiseInit(this); 45 var promise = PromiseInit(this);
44 try { 46 try {
45 %DebugPushPromise(promise); 47 %DebugPushPromise(promise);
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 PromiseCreate = function PromiseCreate() { 154 PromiseCreate = function PromiseCreate() {
153 return new $Promise(PromiseNopResolver) 155 return new $Promise(PromiseNopResolver)
154 } 156 }
155 157
156 PromiseResolve = function PromiseResolve(promise, x) { 158 PromiseResolve = function PromiseResolve(promise, x) {
157 PromiseDone(promise, +1, x, promiseOnResolve) 159 PromiseDone(promise, +1, x, promiseOnResolve)
158 } 160 }
159 161
160 PromiseReject = function PromiseReject(promise, r) { 162 PromiseReject = function PromiseReject(promise, r) {
161 // Check promise status to confirm that this reject has an effect. 163 // Check promise status to confirm that this reject has an effect.
162 // Check promiseDebug property to avoid duplicate event. 164 // Call runtime for callbacks to the debugger or for unhandled reject.
163 if (DEBUG_IS_ACTIVE && 165 if (GET_PRIVATE(promise, promiseStatus) == 0 &&
164 GET_PRIVATE(promise, promiseStatus) == 0 && 166 (DEBUG_IS_ACTIVE || !HAS_DEFINED_PRIVATE(promise, promiseHasHandler))) {
165 !HAS_DEFINED_PRIVATE(promise, promiseDebug)) { 167 %PromiseRejectEvent(promise, r);
166 %DebugPromiseRejectEvent(promise, r);
167 } 168 }
168 PromiseDone(promise, -1, r, promiseOnReject) 169 PromiseDone(promise, -1, r, promiseOnReject)
169 } 170 }
170 171
171 // Convenience. 172 // Convenience.
172 173
173 function PromiseDeferred() { 174 function PromiseDeferred() {
174 if (this === $Promise) { 175 if (this === $Promise) {
175 // Optimized case, avoid extra closure. 176 // Optimized case, avoid extra closure.
176 var promise = PromiseInit(new $Promise(promiseRaw)); 177 var promise = PromiseInit(new $Promise(promiseRaw));
(...skipping 15 matching lines...) Expand all
192 function PromiseResolved(x) { 193 function PromiseResolved(x) {
193 if (this === $Promise) { 194 if (this === $Promise) {
194 // Optimized case, avoid extra closure. 195 // Optimized case, avoid extra closure.
195 return PromiseSet(new $Promise(promiseRaw), +1, x); 196 return PromiseSet(new $Promise(promiseRaw), +1, x);
196 } else { 197 } else {
197 return new this(function(resolve, reject) { resolve(x) }); 198 return new this(function(resolve, reject) { resolve(x) });
198 } 199 }
199 } 200 }
200 201
201 function PromiseRejected(r) { 202 function PromiseRejected(r) {
203 var promise;
202 if (this === $Promise) { 204 if (this === $Promise) {
203 // Optimized case, avoid extra closure. 205 // Optimized case, avoid extra closure.
204 return PromiseSet(new $Promise(promiseRaw), -1, r); 206 promise = PromiseSet(new $Promise(promiseRaw), -1, r);
207 %PromiseRejectEvent(promise, r);
205 } else { 208 } else {
206 return new this(function(resolve, reject) { reject(r) }); 209 promise = new this(function(resolve, reject) { reject(r) });
207 } 210 }
211 return promise;
208 } 212 }
209 213
210 // Simple chaining. 214 // Simple chaining.
211 215
212 PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a. 216 PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a.
213 // flatMap 217 // flatMap
214 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; 218 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
215 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; 219 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
216 var deferred = %_CallFunction(this.constructor, PromiseDeferred); 220 var deferred = %_CallFunction(this.constructor, PromiseDeferred);
217 switch (GET_PRIVATE(this, promiseStatus)) { 221 switch (GET_PRIVATE(this, promiseStatus)) {
218 case UNDEFINED: 222 case UNDEFINED:
219 throw MakeTypeError('not_a_promise', [this]); 223 throw MakeTypeError('not_a_promise', [this]);
220 case 0: // Pending 224 case 0: // Pending
221 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred); 225 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
222 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred); 226 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
223 break; 227 break;
224 case +1: // Resolved 228 case +1: // Resolved
225 PromiseEnqueue(GET_PRIVATE(this, promiseValue), 229 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
226 [onResolve, deferred], 230 [onResolve, deferred],
227 +1); 231 +1);
228 break; 232 break;
229 case -1: // Rejected 233 case -1: // Rejected
234 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
235 // Promise has already been rejected, but had no handler.
236 // Revoke previously triggered reject event.
237 %PromiseRevokeReject(this);
238 }
230 PromiseEnqueue(GET_PRIVATE(this, promiseValue), 239 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
231 [onReject, deferred], 240 [onReject, deferred],
232 -1); 241 -1);
233 break; 242 break;
234 } 243 }
244 // Mark this promise as having handler.
245 SET_PRIVATE(this, promiseHasHandler, true);
235 if (DEBUG_IS_ACTIVE) { 246 if (DEBUG_IS_ACTIVE) {
236 %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this }); 247 %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
237 } 248 }
238 return deferred.promise; 249 return deferred.promise;
239 } 250 }
240 251
241 PromiseCatch = function PromiseCatch(onReject) { 252 PromiseCatch = function PromiseCatch(onReject) {
242 return this.then(UNDEFINED, onReject); 253 return this.then(UNDEFINED, onReject);
243 } 254 }
244 255
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 } 329 }
319 } catch (e) { 330 } catch (e) {
320 deferred.reject(e) 331 deferred.reject(e)
321 } 332 }
322 return deferred.promise; 333 return deferred.promise;
323 } 334 }
324 335
325 336
326 // Utility for debugger 337 // Utility for debugger
327 338
328 function PromiseHasRejectHandlerRecursive(promise) { 339 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
329 var queue = GET_PRIVATE(promise, promiseOnReject); 340 var queue = GET_PRIVATE(promise, promiseOnReject);
330 if (IS_UNDEFINED(queue)) return false; 341 if (IS_UNDEFINED(queue)) return false;
331 // Do a depth first search for a reject handler that's not
332 // the default PromiseIdRejectHandler.
333 for (var i = 0; i < queue.length; i += 2) { 342 for (var i = 0; i < queue.length; i += 2) {
334 if (queue[i] != PromiseIdRejectHandler) return true; 343 if (queue[i] != PromiseIdRejectHandler) return true;
335 if (PromiseHasRejectHandlerRecursive(queue[i + 1].promise)) return true; 344 if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
345 return true;
346 }
336 } 347 }
337 return false; 348 return false;
338 } 349 }
339 350
340 PromiseHasRejectHandler = function PromiseHasRejectHandler() { 351 // Return whether the promise will be handled by a user-defined reject
341 // Mark promise as already having triggered a reject event. 352 // handler somewhere down the promise chain. For this, we do a depth-first
342 SET_PRIVATE(this, promiseDebug, true); 353 // search for a reject handler that's not the default PromiseIdRejectHandler.
343 return PromiseHasRejectHandlerRecursive(this); 354 PromiseHasUserDefinedRejectHandler =
355 function PromiseHasUserDefinedRejectHandler() {
356 return PromiseHasUserDefinedRejectHandlerRecursive(this);
344 }; 357 };
345 358
346 // ------------------------------------------------------------------- 359 // -------------------------------------------------------------------
347 // Install exported functions. 360 // Install exported functions.
348 361
349 %CheckIsBootstrapping(); 362 %CheckIsBootstrapping();
350 %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM); 363 %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM);
351 InstallFunctions($Promise, DONT_ENUM, [ 364 InstallFunctions($Promise, DONT_ENUM, [
352 "defer", PromiseDeferred, 365 "defer", PromiseDeferred,
353 "accept", PromiseResolved, 366 "accept", PromiseResolved,
354 "reject", PromiseRejected, 367 "reject", PromiseRejected,
355 "all", PromiseAll, 368 "all", PromiseAll,
356 "race", PromiseOne, 369 "race", PromiseOne,
357 "resolve", PromiseCast 370 "resolve", PromiseCast
358 ]); 371 ]);
359 InstallFunctions($Promise.prototype, DONT_ENUM, [ 372 InstallFunctions($Promise.prototype, DONT_ENUM, [
360 "chain", PromiseChain, 373 "chain", PromiseChain,
361 "then", PromiseThen, 374 "then", PromiseThen,
362 "catch", PromiseCatch 375 "catch", PromiseCatch
363 ]); 376 ]);
364 377
365 })(); 378 })();
OLDNEW
« include/v8.h ('K') | « src/isolate.cc ('k') | src/runtime/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698