| Index: src/promise.js
|
| diff --git a/src/promise.js b/src/promise.js
|
| deleted file mode 100644
|
| index 728a23157b1d8e747251cbfb5cee6dddef52a083..0000000000000000000000000000000000000000
|
| --- a/src/promise.js
|
| +++ /dev/null
|
| @@ -1,403 +0,0 @@
|
| -// Copyright 2012 the V8 project authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -(function(global, utils, extrasUtils) {
|
| -
|
| -"use strict";
|
| -
|
| -%CheckIsBootstrapping();
|
| -
|
| -// -------------------------------------------------------------------
|
| -// Imports
|
| -
|
| -var InternalArray = utils.InternalArray;
|
| -var promiseHasHandlerSymbol =
|
| - utils.ImportNow("promise_has_handler_symbol");
|
| -var promiseOnRejectSymbol = utils.ImportNow("promise_on_reject_symbol");
|
| -var promiseOnResolveSymbol =
|
| - utils.ImportNow("promise_on_resolve_symbol");
|
| -var promiseRawSymbol = utils.ImportNow("promise_raw_symbol");
|
| -var promiseStatusSymbol = utils.ImportNow("promise_status_symbol");
|
| -var promiseValueSymbol = utils.ImportNow("promise_value_symbol");
|
| -var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
|
| -
|
| -// -------------------------------------------------------------------
|
| -
|
| -// Status values: 0 = pending, +1 = resolved, -1 = rejected
|
| -var lastMicrotaskId = 0;
|
| -
|
| -var GlobalPromise = function Promise(resolver) {
|
| - if (resolver === promiseRawSymbol) return;
|
| - if (!%_IsConstructCall()) throw MakeTypeError(kNotAPromise, this);
|
| - if (!IS_CALLABLE(resolver))
|
| - throw MakeTypeError(kResolverNotAFunction, resolver);
|
| - var promise = PromiseInit(this);
|
| - try {
|
| - %DebugPushPromise(promise, Promise);
|
| - resolver(function(x) { PromiseResolve(promise, x) },
|
| - function(r) { PromiseReject(promise, r) });
|
| - } catch (e) {
|
| - PromiseReject(promise, e);
|
| - } finally {
|
| - %DebugPopPromise();
|
| - }
|
| -}
|
| -
|
| -// Core functionality.
|
| -
|
| -function PromiseSet(promise, status, value, onResolve, onReject) {
|
| - SET_PRIVATE(promise, promiseStatusSymbol, status);
|
| - SET_PRIVATE(promise, promiseValueSymbol, value);
|
| - SET_PRIVATE(promise, promiseOnResolveSymbol, onResolve);
|
| - SET_PRIVATE(promise, promiseOnRejectSymbol, onReject);
|
| - if (DEBUG_IS_ACTIVE) {
|
| - %DebugPromiseEvent({ promise: promise, status: status, value: value });
|
| - }
|
| - return promise;
|
| -}
|
| -
|
| -function PromiseCreateAndSet(status, value) {
|
| - var promise = new GlobalPromise(promiseRawSymbol);
|
| - // If debug is active, notify about the newly created promise first.
|
| - if (DEBUG_IS_ACTIVE) PromiseSet(promise, 0, UNDEFINED);
|
| - return PromiseSet(promise, status, value);
|
| -}
|
| -
|
| -function PromiseInit(promise) {
|
| - return PromiseSet(
|
| - promise, 0, UNDEFINED, new InternalArray, new InternalArray)
|
| -}
|
| -
|
| -function PromiseDone(promise, status, value, promiseQueue) {
|
| - if (GET_PRIVATE(promise, promiseStatusSymbol) === 0) {
|
| - var tasks = GET_PRIVATE(promise, promiseQueue);
|
| - if (tasks.length) PromiseEnqueue(value, tasks, status);
|
| - PromiseSet(promise, status, value);
|
| - }
|
| -}
|
| -
|
| -function PromiseCoerce(constructor, x) {
|
| - if (!IsPromise(x) && IS_SPEC_OBJECT(x)) {
|
| - var then;
|
| - try {
|
| - then = x.then;
|
| - } catch(r) {
|
| - return %_CallFunction(constructor, r, PromiseRejected);
|
| - }
|
| - if (IS_CALLABLE(then)) {
|
| - var deferred = %_CallFunction(constructor, PromiseDeferred);
|
| - try {
|
| - %_Call(then, x, deferred.resolve, deferred.reject);
|
| - } catch(r) {
|
| - deferred.reject(r);
|
| - }
|
| - return deferred.promise;
|
| - }
|
| - }
|
| - return x;
|
| -}
|
| -
|
| -function PromiseHandle(value, handler, deferred) {
|
| - try {
|
| - %DebugPushPromise(deferred.promise, PromiseHandle);
|
| - DEBUG_PREPARE_STEP_IN_IF_STEPPING(handler);
|
| - var result = handler(value);
|
| - if (result === deferred.promise)
|
| - throw MakeTypeError(kPromiseCyclic, result);
|
| - else if (IsPromise(result))
|
| - %_CallFunction(result, deferred.resolve, deferred.reject, PromiseChain);
|
| - else
|
| - deferred.resolve(result);
|
| - } catch (exception) {
|
| - try { deferred.reject(exception); } catch (e) { }
|
| - } finally {
|
| - %DebugPopPromise();
|
| - }
|
| -}
|
| -
|
| -function PromiseEnqueue(value, tasks, status) {
|
| - var id, name, instrumenting = DEBUG_IS_ACTIVE;
|
| - %EnqueueMicrotask(function() {
|
| - if (instrumenting) {
|
| - %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
|
| - }
|
| - for (var i = 0; i < tasks.length; i += 2) {
|
| - PromiseHandle(value, tasks[i], tasks[i + 1])
|
| - }
|
| - if (instrumenting) {
|
| - %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
|
| - }
|
| - });
|
| - if (instrumenting) {
|
| - id = ++lastMicrotaskId;
|
| - name = status > 0 ? "Promise.resolve" : "Promise.reject";
|
| - %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
|
| - }
|
| -}
|
| -
|
| -function PromiseIdResolveHandler(x) { return x }
|
| -function PromiseIdRejectHandler(r) { throw r }
|
| -
|
| -function PromiseNopResolver() {}
|
| -
|
| -// -------------------------------------------------------------------
|
| -// Define exported functions.
|
| -
|
| -// For bootstrapper.
|
| -
|
| -function IsPromise(x) {
|
| - return IS_SPEC_OBJECT(x) && HAS_DEFINED_PRIVATE(x, promiseStatusSymbol);
|
| -}
|
| -
|
| -function PromiseCreate() {
|
| - return new GlobalPromise(PromiseNopResolver)
|
| -}
|
| -
|
| -function PromiseResolve(promise, x) {
|
| - PromiseDone(promise, +1, x, promiseOnResolveSymbol)
|
| -}
|
| -
|
| -function PromiseReject(promise, r) {
|
| - // Check promise status to confirm that this reject has an effect.
|
| - // Call runtime for callbacks to the debugger or for unhandled reject.
|
| - if (GET_PRIVATE(promise, promiseStatusSymbol) == 0) {
|
| - var debug_is_active = DEBUG_IS_ACTIVE;
|
| - if (debug_is_active ||
|
| - !HAS_DEFINED_PRIVATE(promise, promiseHasHandlerSymbol)) {
|
| - %PromiseRejectEvent(promise, r, debug_is_active);
|
| - }
|
| - }
|
| - PromiseDone(promise, -1, r, promiseOnRejectSymbol)
|
| -}
|
| -
|
| -// Convenience.
|
| -
|
| -function PromiseDeferred() {
|
| - if (this === GlobalPromise) {
|
| - // Optimized case, avoid extra closure.
|
| - var promise = PromiseInit(new GlobalPromise(promiseRawSymbol));
|
| - return {
|
| - promise: promise,
|
| - resolve: function(x) { PromiseResolve(promise, x) },
|
| - reject: function(r) { PromiseReject(promise, r) }
|
| - };
|
| - } else {
|
| - var result = {promise: UNDEFINED, reject: UNDEFINED, resolve: UNDEFINED};
|
| - result.promise = new this(function(resolve, reject) {
|
| - result.resolve = resolve;
|
| - result.reject = reject;
|
| - });
|
| - return result;
|
| - }
|
| -}
|
| -
|
| -function PromiseResolved(x) {
|
| - if (this === GlobalPromise) {
|
| - // Optimized case, avoid extra closure.
|
| - return PromiseCreateAndSet(+1, x);
|
| - } else {
|
| - return new this(function(resolve, reject) { resolve(x) });
|
| - }
|
| -}
|
| -
|
| -function PromiseRejected(r) {
|
| - var promise;
|
| - if (this === GlobalPromise) {
|
| - // Optimized case, avoid extra closure.
|
| - promise = PromiseCreateAndSet(-1, r);
|
| - // The debug event for this would always be an uncaught promise reject,
|
| - // which is usually simply noise. Do not trigger that debug event.
|
| - %PromiseRejectEvent(promise, r, false);
|
| - } else {
|
| - promise = new this(function(resolve, reject) { reject(r) });
|
| - }
|
| - return promise;
|
| -}
|
| -
|
| -// Simple chaining.
|
| -
|
| -function PromiseChain(onResolve, onReject) { // a.k.a. flatMap
|
| - onResolve = IS_UNDEFINED(onResolve) ? PromiseIdResolveHandler : onResolve;
|
| - onReject = IS_UNDEFINED(onReject) ? PromiseIdRejectHandler : onReject;
|
| - var deferred = %_CallFunction(this.constructor, PromiseDeferred);
|
| - switch (GET_PRIVATE(this, promiseStatusSymbol)) {
|
| - case UNDEFINED:
|
| - throw MakeTypeError(kNotAPromise, this);
|
| - case 0: // Pending
|
| - GET_PRIVATE(this, promiseOnResolveSymbol).push(onResolve, deferred);
|
| - GET_PRIVATE(this, promiseOnRejectSymbol).push(onReject, deferred);
|
| - break;
|
| - case +1: // Resolved
|
| - PromiseEnqueue(GET_PRIVATE(this, promiseValueSymbol),
|
| - [onResolve, deferred],
|
| - +1);
|
| - break;
|
| - case -1: // Rejected
|
| - if (!HAS_DEFINED_PRIVATE(this, promiseHasHandlerSymbol)) {
|
| - // Promise has already been rejected, but had no handler.
|
| - // Revoke previously triggered reject event.
|
| - %PromiseRevokeReject(this);
|
| - }
|
| - PromiseEnqueue(GET_PRIVATE(this, promiseValueSymbol),
|
| - [onReject, deferred],
|
| - -1);
|
| - break;
|
| - }
|
| - // Mark this promise as having handler.
|
| - SET_PRIVATE(this, promiseHasHandlerSymbol, true);
|
| - if (DEBUG_IS_ACTIVE) {
|
| - %DebugPromiseEvent({ promise: deferred.promise, parentPromise: this });
|
| - }
|
| - return deferred.promise;
|
| -}
|
| -
|
| -function PromiseCatch(onReject) {
|
| - return this.then(UNDEFINED, onReject);
|
| -}
|
| -
|
| -// Multi-unwrapped chaining with thenable coercion.
|
| -
|
| -function PromiseThen(onResolve, onReject) {
|
| - onResolve = IS_CALLABLE(onResolve) ? onResolve : PromiseIdResolveHandler;
|
| - onReject = IS_CALLABLE(onReject) ? onReject : PromiseIdRejectHandler;
|
| - var that = this;
|
| - var constructor = this.constructor;
|
| - return %_CallFunction(
|
| - this,
|
| - function(x) {
|
| - x = PromiseCoerce(constructor, x);
|
| - if (x === that) {
|
| - DEBUG_PREPARE_STEP_IN_IF_STEPPING(onReject);
|
| - return onReject(MakeTypeError(kPromiseCyclic, x));
|
| - } else if (IsPromise(x)) {
|
| - return x.then(onResolve, onReject);
|
| - } else {
|
| - DEBUG_PREPARE_STEP_IN_IF_STEPPING(onResolve);
|
| - return onResolve(x);
|
| - }
|
| - },
|
| - onReject,
|
| - PromiseChain
|
| - );
|
| -}
|
| -
|
| -// Combinators.
|
| -
|
| -function PromiseCast(x) {
|
| - if (IsPromise(x) && x.constructor === this) {
|
| - return x;
|
| - } else {
|
| - return new this(function(resolve) { resolve(x) });
|
| - }
|
| -}
|
| -
|
| -function PromiseAll(iterable) {
|
| - var deferred = %_CallFunction(this, PromiseDeferred);
|
| - var resolutions = [];
|
| - try {
|
| - var count = 0;
|
| - var i = 0;
|
| - for (var value of iterable) {
|
| - this.resolve(value).then(
|
| - // Nested scope to get closure over current i.
|
| - // TODO(arv): Use an inner let binding once available.
|
| - (function(i) {
|
| - return function(x) {
|
| - resolutions[i] = x;
|
| - if (--count === 0) deferred.resolve(resolutions);
|
| - }
|
| - })(i),
|
| - function(r) { deferred.reject(r); });
|
| - ++i;
|
| - ++count;
|
| - }
|
| -
|
| - if (count === 0) {
|
| - deferred.resolve(resolutions);
|
| - }
|
| -
|
| - } catch (e) {
|
| - deferred.reject(e)
|
| - }
|
| - return deferred.promise;
|
| -}
|
| -
|
| -function PromiseRace(iterable) {
|
| - var deferred = %_CallFunction(this, PromiseDeferred);
|
| - try {
|
| - for (var value of iterable) {
|
| - this.resolve(value).then(
|
| - function(x) { deferred.resolve(x) },
|
| - function(r) { deferred.reject(r) });
|
| - }
|
| - } catch (e) {
|
| - deferred.reject(e)
|
| - }
|
| - return deferred.promise;
|
| -}
|
| -
|
| -
|
| -// Utility for debugger
|
| -
|
| -function PromiseHasUserDefinedRejectHandlerRecursive(promise) {
|
| - var queue = GET_PRIVATE(promise, promiseOnRejectSymbol);
|
| - if (IS_UNDEFINED(queue)) return false;
|
| - for (var i = 0; i < queue.length; i += 2) {
|
| - if (queue[i] != PromiseIdRejectHandler) return true;
|
| - if (PromiseHasUserDefinedRejectHandlerRecursive(queue[i + 1].promise)) {
|
| - return true;
|
| - }
|
| - }
|
| - return false;
|
| -}
|
| -
|
| -// Return whether the promise will be handled by a user-defined reject
|
| -// handler somewhere down the promise chain. For this, we do a depth-first
|
| -// search for a reject handler that's not the default PromiseIdRejectHandler.
|
| -function PromiseHasUserDefinedRejectHandler() {
|
| - return PromiseHasUserDefinedRejectHandlerRecursive(this);
|
| -};
|
| -
|
| -// -------------------------------------------------------------------
|
| -// Install exported functions.
|
| -
|
| -%AddNamedProperty(global, 'Promise', GlobalPromise, DONT_ENUM);
|
| -%AddNamedProperty(GlobalPromise.prototype, toStringTagSymbol, "Promise",
|
| - DONT_ENUM | READ_ONLY);
|
| -
|
| -utils.InstallFunctions(GlobalPromise, DONT_ENUM, [
|
| - "defer", PromiseDeferred,
|
| - "accept", PromiseResolved,
|
| - "reject", PromiseRejected,
|
| - "all", PromiseAll,
|
| - "race", PromiseRace,
|
| - "resolve", PromiseCast
|
| -]);
|
| -
|
| -utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
|
| - "chain", PromiseChain,
|
| - "then", PromiseThen,
|
| - "catch", PromiseCatch
|
| -]);
|
| -
|
| -%InstallToContext([
|
| - "promise_catch", PromiseCatch,
|
| - "promise_chain", PromiseChain,
|
| - "promise_create", PromiseCreate,
|
| - "promise_has_user_defined_reject_handler", PromiseHasUserDefinedRejectHandler,
|
| - "promise_reject", PromiseReject,
|
| - "promise_resolve", PromiseResolve,
|
| - "promise_then", PromiseThen,
|
| -]);
|
| -
|
| -// This allows extras to create promises quickly without building extra
|
| -// resolve/reject closures, and allows them to later resolve and reject any
|
| -// promise without having to hold on to those closures forever.
|
| -utils.InstallFunctions(extrasUtils, 0, [
|
| - "createPromise", PromiseCreate,
|
| - "resolvePromise", PromiseResolve,
|
| - "rejectPromise", PromiseReject
|
| -]);
|
| -
|
| -})
|
|
|