Deprecate nonstandard Promise.prototype.done

Summary:
Deprecates the nonstandard `Promise.prototype.done` method. This also removes one call site within React Native itself that relied on this method.

As part of this we are also removing React Native's custom Flow definition for `Promise` in favour of the standard one built into Flow. This will flag uses of `done` as type errors for anyone using the default app template's `.flowconfig`.

In a future release of React Native, we will remove the `done` method from the built-in `Promise` polyfill.

Changelog:
[General][Deprecated] - Deprecate the Promise.prototype.done method and log a warning when it's called in development.

Reviewed By: yungsters

Differential Revision: D34222667

fbshipit-source-id: 4b9708ac20c45b3966fdb93e883ab7f8d80017c1
This commit is contained in:
Moti Zilberman
2022-02-17 09:15:03 -08:00
committed by Facebook GitHub Bot
parent 062c1f7277
commit 35800962c1
4 changed files with 37 additions and 62 deletions
+32
View File
@@ -11,6 +11,7 @@
'use strict';
const {polyfillGlobal} = require('../Utilities/PolyfillFunctions');
const warnOnce = require('../Utilities/warnOnce');
/**
* Set up Promise. The native Promise implementation throws the following error:
@@ -36,3 +37,34 @@ if (global?.HermesInternal?.hasPromise?.()) {
} else {
polyfillGlobal('Promise', () => require('../Promise'));
}
if (__DEV__) {
// $FlowFixMe
const done = Promise.prototype.done;
if (done != null) {
let depth = 0;
/* eslint-disable no-extend-native */
// $FlowFixMe
Promise.prototype.done = function () {
++depth;
try {
// Avoid infinite recursion if done() happens to be triggered by warnOnce.
if (depth === 1) {
// Warn once per unique call stack. Not super efficient, but we're in
// __DEV__ and .done() calls are rare to begin with.
const key = new Error().stack;
warnOnce(
key,
'Promise.prototype.done(): This nonstandard polyfill ' +
'has been deprecated and will be removed in a future release. ' +
'Please instead use `.then()`.',
);
}
} finally {
--depth;
}
return done.apply(this, arguments);
};
/* eslint-enable no-extend-native */
}
}
@@ -91,7 +91,6 @@ const InteractionManager = {
onFulfill?: ?(void) => ?(Promise<U> | U),
onReject?: ?(error: mixed) => ?(Promise<U> | U),
) => Promise<U>,
done: () => void,
cancel: () => void,
...
} {
@@ -110,16 +109,6 @@ const InteractionManager = {
return {
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
then: promise.then.bind(promise),
done: (...args) => {
// $FlowFixMe[method-unbinding] added when improving typing for this parameters
if (promise.done) {
return promise.done(...args);
} else {
console.warn(
'Tried to call done when not supported by current Promise implementation.',
);
}
},
cancel: function () {
_taskQueue.cancelTasks(tasks);
},
+5 -4
View File
@@ -171,10 +171,11 @@ class TaskQueue {
this.hasTasksToProcess() && this._onMoreTasks();
})
.catch(ex => {
ex.message = `TaskQueue: Error resolving Promise in task ${task.name}: ${ex.message}`;
throw ex;
})
.done();
setTimeout(() => {
ex.message = `TaskQueue: Error resolving Promise in task ${task.name}: ${ex.message}`;
throw ex;
}, 0);
});
}
}
-47
View File
@@ -1,47 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
// These annotations are copy/pasted from the built-in Flow definitions for
// Native Promises with some non-standard APIs added in
declare class Promise<+R> {
constructor(
callback: (
resolve: (result?: Promise<R> | R) => void,
reject: (error?: any) => void,
) => mixed,
): void;
then<U>(
onFulfill?: ?(value: R) => Promise<U> | ?U,
onReject?: ?(error: any) => Promise<U> | ?U,
): Promise<U>;
catch<U>(onReject?: (error: any) => ?Promise<U> | U): Promise<U>;
static resolve<T>(object?: Promise<T> | T): Promise<T>;
static reject<T>(error?: any): Promise<T>;
static all<T: Iterable<mixed>>(
promises: T,
): Promise<$TupleMap<T, typeof $await>>;
static race<T>(promises: Array<Promise<T>>): Promise<T>;
// Non-standard APIs
// See https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/__forks__/Promise.native.js#L21
finally<U>(onFinally?: ?(value: any) => Promise<U> | U): Promise<U>;
done<U>(
onFulfill?: ?(value: R) => mixed,
onReject?: ?(error: any) => mixed,
): void;
static cast<T>(object?: T): Promise<T>;
}