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

Side by Side Diff: src/js/promise.js

Issue 1534813005: [promise] Make Promise.all match spec, and always respect [[AlreadyResolved]] (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years 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
« no previous file with comments | « no previous file | no next file » | 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 (function(global, utils, extrasUtils) { 5 (function(global, utils, extrasUtils) {
6 6
7 "use strict"; 7 "use strict";
8 8
9 %CheckIsBootstrapping(); 9 %CheckIsBootstrapping();
10 10
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 62
63 var GlobalPromise = function Promise(resolver) { 63 var GlobalPromise = function Promise(resolver) {
64 if (resolver === promiseRawSymbol) { 64 if (resolver === promiseRawSymbol) {
65 return %NewObject(GlobalPromise, new.target); 65 return %NewObject(GlobalPromise, new.target);
66 } 66 }
67 if (IS_UNDEFINED(new.target)) throw MakeTypeError(kNotAPromise, this); 67 if (IS_UNDEFINED(new.target)) throw MakeTypeError(kNotAPromise, this);
68 if (!IS_CALLABLE(resolver)) 68 if (!IS_CALLABLE(resolver))
69 throw MakeTypeError(kResolverNotAFunction, resolver); 69 throw MakeTypeError(kResolverNotAFunction, resolver);
70 70
71 var promise = PromiseInit(%NewObject(GlobalPromise, new.target)); 71 var promise = PromiseInit(%NewObject(GlobalPromise, new.target));
72 var callbacks = CreateResolvingFunctions(promise);
72 73
73 try { 74 try {
74 %DebugPushPromise(promise, Promise); 75 %DebugPushPromise(promise, Promise);
75 var callbacks = CreateResolvingFunctions(promise);
76 resolver(callbacks.resolve, callbacks.reject); 76 resolver(callbacks.resolve, callbacks.reject);
77 } catch (e) { 77 } catch (e) {
78 PromiseReject(promise, e); 78 callbacks.reject(e);
Dan Ehrenberg 2016/01/04 02:49:15 I think this needs to be %_Call(callbacks.reject,
79 } finally { 79 } finally {
80 %DebugPopPromise(); 80 %DebugPopPromise();
81 } 81 }
82 82
83 return promise; 83 return promise;
84 } 84 }
85 85
86 // Core functionality. 86 // Core functionality.
87 87
88 function PromiseSet(promise, status, value, onResolve, onReject) { 88 function PromiseSet(promise, status, value, onResolve, onReject) {
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 if (IS_RECEIVER(x)) { 197 if (IS_RECEIVER(x)) {
198 // 25.4.1.3.2 steps 8-12 198 // 25.4.1.3.2 steps 8-12
199 try { 199 try {
200 var then = x.then; 200 var then = x.then;
201 } catch (e) { 201 } catch (e) {
202 return PromiseReject(promise, e); 202 return PromiseReject(promise, e);
203 } 203 }
204 if (IS_CALLABLE(then)) { 204 if (IS_CALLABLE(then)) {
205 // PromiseResolveThenableJob 205 // PromiseResolveThenableJob
206 return %EnqueueMicrotask(function() { 206 return %EnqueueMicrotask(function() {
207 var callbacks = CreateResolvingFunctions(promise);
207 try { 208 try {
208 var callbacks = CreateResolvingFunctions(promise);
209 %_Call(then, x, callbacks.resolve, callbacks.reject); 209 %_Call(then, x, callbacks.resolve, callbacks.reject);
210 } catch (e) { 210 } catch (e) {
211 PromiseReject(promise, e); 211 callbacks.reject(promise, e);
Dan Ehrenberg 2016/01/04 02:49:15 Here too
212 } 212 }
213 }); 213 });
214 } 214 }
215 } 215 }
216 PromiseDone(promise, +1, x, promiseOnResolveSymbol); 216 PromiseDone(promise, +1, x, promiseOnResolveSymbol);
217 } 217 }
218 } 218 }
219 219
220 function PromiseReject(promise, r) { 220 function PromiseReject(promise, r) {
221 // Check promise status to confirm that this reject has an effect. 221 // Check promise status to confirm that this reject has an effect.
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 355
356 function PromiseCast(x) { 356 function PromiseCast(x) {
357 if (IsPromise(x) && x.constructor === this) { 357 if (IsPromise(x) && x.constructor === this) {
358 return x; 358 return x;
359 } else { 359 } else {
360 return new this(function(resolve) { resolve(x) }); 360 return new this(function(resolve) { resolve(x) });
361 } 361 }
362 } 362 }
363 363
364 function PromiseAll(iterable) { 364 function PromiseAll(iterable) {
365 if (!IS_RECEIVER(this)) {
366 throw MakeTypeError(kCalledOnNonObject, "Promise.all");
367 }
368
365 var deferred = NewPromiseCapability(this); 369 var deferred = NewPromiseCapability(this);
366 var resolutions = []; 370 var resolutions = [];
367 try { 371 try {
368 var count = 0; 372 var count = 1;
369 var i = 0; 373 var i = 0;
370 for (var value of iterable) { 374 for (var value of iterable) {
371 var reject = function(r) { deferred.reject(r) }; 375 resolutions[i] = UNDEFINED;
372 this.resolve(value).then( 376 var nextPromise = this.resolve(value);
373 // Nested scope to get closure over current i. 377 ++count;
374 // TODO(arv): Use an inner let binding once available. 378 nextPromise.then(
375 (function(i) { 379 CreateResolveElementFunction(i, resolutions, deferred),
376 return function(x) { 380 deferred.reject);
377 resolutions[i] = x; 381 SET_PRIVATE(deferred.reject, promiseCombinedDeferredSymbol, deferred);
378 if (--count === 0) deferred.resolve(resolutions);
379 }
380 })(i), reject);
381 SET_PRIVATE(reject, promiseCombinedDeferredSymbol, deferred);
382 ++i; 382 ++i;
383 ++count;
384 } 383 }
385 384
386 if (count === 0) { 385 // 6.d
386 if (--count === 0) {
387 deferred.resolve(resolutions); 387 deferred.resolve(resolutions);
388 } 388 }
389 389
390 } catch (e) { 390 } catch (e) {
391 deferred.reject(e) 391 deferred.reject(e)
392 } 392 }
393 return deferred.promise; 393 return deferred.promise;
394
395 function CreateResolveElementFunction(index, values, promiseCapability) {
396 var alreadyCalled = false;
397 return function(x) {
398 if (alreadyCalled === true) return;
399 alreadyCalled = true;
400 values[index] = x;
401 if (--count === 0) promiseCapability.resolve(values);
402 };
403 }
394 } 404 }
395 405
396 function PromiseRace(iterable) { 406 function PromiseRace(iterable) {
397 var deferred = NewPromiseCapability(this); 407 var deferred = NewPromiseCapability(this);
398 try { 408 try {
399 for (var value of iterable) { 409 for (var value of iterable) {
400 var reject = function(r) { deferred.reject(r) }; 410 var reject = function(r) { deferred.reject(r) };
401 this.resolve(value).then(function(x) { deferred.resolve(x) }, reject); 411 this.resolve(value).then(function(x) { deferred.resolve(x) }, reject);
402 SET_PRIVATE(reject, promiseCombinedDeferredSymbol, deferred); 412 SET_PRIVATE(reject, promiseCombinedDeferredSymbol, deferred);
403 } 413 }
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 [PromiseChain, PromiseDeferred, PromiseResolved].forEach( 488 [PromiseChain, PromiseDeferred, PromiseResolved].forEach(
479 fn => %FunctionRemovePrototype(fn)); 489 fn => %FunctionRemovePrototype(fn));
480 490
481 utils.Export(function(to) { 491 utils.Export(function(to) {
482 to.PromiseChain = PromiseChain; 492 to.PromiseChain = PromiseChain;
483 to.PromiseDeferred = PromiseDeferred; 493 to.PromiseDeferred = PromiseDeferred;
484 to.PromiseResolved = PromiseResolved; 494 to.PromiseResolved = PromiseResolved;
485 }); 495 });
486 496
487 }) 497 })
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698