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

Side by Side Diff: src/promise.js

Issue 600723005: Introduce PromiseRejectCallback. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: 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
« no previous file with comments | « src/isolate.cc ('k') | src/runtime/runtime.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
205 } else { 207 } else {
206 return new this(function(resolve, reject) { reject(r) }); 208 promise = new this(function(resolve, reject) { reject(r) });
207 } 209 }
210 // This promise is expected to have the reject state. Mark it to avoid
211 // triggering an unnecessary callback.
212 SET_PRIVATE(promise, promiseHasHandler, true);
domenic_domenicdenicola.com 2014/09/30 10:30:42 This doesn't seem correct. The promise doesn't hav
Yang 2014/09/30 10:38:50 If I reject a promise by returning a rejected prom
213 return promise;
208 } 214 }
209 215
210 // Simple chaining. 216 // Simple chaining.
211 217
212 PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a. 218 PromiseChain = function PromiseChain(onResolve, onReject) { // a.k.a.
213 // flatMap 219 // flatMap
214 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve; 220 onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
215 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject; 221 onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
216 var deferred = %_CallFunction(this.constructor, PromiseDeferred); 222 var deferred = %_CallFunction(this.constructor, PromiseDeferred);
217 switch (GET_PRIVATE(this, promiseStatus)) { 223 switch (GET_PRIVATE(this, promiseStatus)) {
218 case UNDEFINED: 224 case UNDEFINED:
219 throw MakeTypeError('not_a_promise', [this]); 225 throw MakeTypeError('not_a_promise', [this]);
220 case 0: // Pending 226 case 0: // Pending
221 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred); 227 GET_PRIVATE(this, promiseOnResolve).push(onResolve, deferred);
222 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred); 228 GET_PRIVATE(this, promiseOnReject).push(onReject, deferred);
223 break; 229 break;
224 case +1: // Resolved 230 case +1: // Resolved
225 PromiseEnqueue(GET_PRIVATE(this, promiseValue), 231 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
226 [onResolve, deferred], 232 [onResolve, deferred],
227 +1); 233 +1);
228 break; 234 break;
229 case -1: // Rejected 235 case -1: // Rejected
236 if (!HAS_DEFINED_PRIVATE(this, promiseHasHandler)) {
237 // Promise has already been rejected, but had no handler.
238 // Revoke previously triggered reject event.
239 %PromiseRevokeReject(this);
240 }
230 PromiseEnqueue(GET_PRIVATE(this, promiseValue), 241 PromiseEnqueue(GET_PRIVATE(this, promiseValue),
231 [onReject, deferred], 242 [onReject, deferred],
232 -1); 243 -1);
233 break; 244 break;
234 } 245 }
246 // Mark this promise as having handler.
247 SET_PRIVATE(this, promiseHasHandler, true);
235 if (DEBUG_IS_ACTIVE) { 248 if (DEBUG_IS_ACTIVE) {
236 %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this }); 249 %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
237 } 250 }
238 return deferred.promise; 251 return deferred.promise;
239 } 252 }
240 253
241 PromiseCatch = function PromiseCatch(onReject) { 254 PromiseCatch = function PromiseCatch(onReject) {
242 return this.then(UNDEFINED, onReject); 255 return this.then(UNDEFINED, onReject);
243 } 256 }
244 257
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
318 } 331 }
319 } catch (e) { 332 } catch (e) {
320 deferred.reject(e) 333 deferred.reject(e)
321 } 334 }
322 return deferred.promise; 335 return deferred.promise;
323 } 336 }
324 337
325 338
326 // Utility for debugger 339 // Utility for debugger
327 340
328 function PromiseHasRejectHandlerRecursive(promise) { 341 function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
329 var queue = GET_PRIVATE(promise, promiseOnReject); 342 var queue = GET_PRIVATE(promise, promiseOnReject);
330 if (IS_UNDEFINED(queue)) return false; 343 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) { 344 for (var i = 0; i < queue.length; i += 2) {
334 if (queue[i] != PromiseIdRejectHandler) return true; 345 if (queue[i] != PromiseIdRejectHandler) return true;
335 if (PromiseHasRejectHandlerRecursive(queue[i + 1].promise)) return true; 346 if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
347 return true;
348 }
336 } 349 }
337 return false; 350 return false;
338 } 351 }
339 352
340 PromiseHasRejectHandler = function PromiseHasRejectHandler() { 353 // Return whether the promise will be handled by a user-defined reject
341 // Mark promise as already having triggered a reject event. 354 // handler somewhere down the promise chain. For this, we do a depth-first
342 SET_PRIVATE(this, promiseDebug, true); 355 // search for a reject handler that's not the default PromiseIdRejectHandler.
343 return PromiseHasRejectHandlerRecursive(this); 356 PromiseHasUserDefinedRejectHandler =
357 function PromiseHasUserDefinedRejectHandler() {
358 return PromiseHasUserDefinedRejectHandlerRecursive(this);
344 }; 359 };
345 360
346 // ------------------------------------------------------------------- 361 // -------------------------------------------------------------------
347 // Install exported functions. 362 // Install exported functions.
348 363
349 %CheckIsBootstrapping(); 364 %CheckIsBootstrapping();
350 %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM); 365 %AddNamedProperty(global, 'Promise', $Promise, DONT_ENUM);
351 InstallFunctions($Promise, DONT_ENUM, [ 366 InstallFunctions($Promise, DONT_ENUM, [
352 "defer", PromiseDeferred, 367 "defer", PromiseDeferred,
353 "accept", PromiseResolved, 368 "accept", PromiseResolved,
354 "reject", PromiseRejected, 369 "reject", PromiseRejected,
355 "all", PromiseAll, 370 "all", PromiseAll,
356 "race", PromiseOne, 371 "race", PromiseOne,
357 "resolve", PromiseCast 372 "resolve", PromiseCast
358 ]); 373 ]);
359 InstallFunctions($Promise.prototype, DONT_ENUM, [ 374 InstallFunctions($Promise.prototype, DONT_ENUM, [
360 "chain", PromiseChain, 375 "chain", PromiseChain,
361 "then", PromiseThen, 376 "then", PromiseThen,
362 "catch", PromiseCatch 377 "catch", PromiseCatch
363 ]); 378 ]);
364 379
365 })(); 380 })();
OLDNEW
« no previous file with comments | « src/isolate.cc ('k') | src/runtime/runtime.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698