Изначально этот файл демонстрировал внутреннюю операцию NewPromiseCapability на языке js. Не так давно в 14 версию ECMAScript интегрировали API Promise.withResolvers. И всвязи с этим я хочу кое-что пояснить.
Для начала вспомним операцию NewPromiseCapability:
function NewPromiseCapability(C){
if (!(C.prototype && C.prototype.constructor === C && typeof C === "function")) throw TypeError("C is not a constructor");
const resolvingFunctions = {
resolve: undefined,
reject: undefined,
};
const closure = function(resolve, reject){
if (resolvingFunctions.resolve !== undefined) throw TypeError("Resolve function is not undefined");
if (resolvingFunctions.reject !== undefined) throw TypeError("Reject function is not undefined");
resolvingFunctions.resolve = resolve;
resolvingFunctions.reject = reject;
};
const promise = Reflect.construct(C, [closure]);
if (typeof resolvingFunctions.resolve !== "function") throw TypeError("Resolve function is not callable");
if (typeof resolvingFunctions.reject !== "function") throw TypeError("Reject function is not callable");
return {
"[[Promise]]": promise,
"[[Resolve]]": resolvingFunctions.resolve,
"[[Reject]]": resolvingFunctions.reject,
};
}
Как вы можете заметить данная операция возвращает триплет свойств: [[Promise]]
, [[Resolve]]
и [[Reject]]
- тут все понятно.
Пример использования данной операции будет такой:
NewPromiseCapability(Promise); /// {[[Promise]]: Promise, [[Resolve]]: ƒ, [[Reject]]: ƒ}
И казалось бы при чем здесь Promise.withResolvers?! А вот при чем! Открываем спецификацию Promise.withResolvers и смотрим на шаги.
Вот демонстрация Promise.withResolvers на js:
function withResolvers() {
const C = this;
const promiseCapability = NewPromiseCapability(C);
const obj = Object.create(Object.prototype);
Object.defineProperty(obj, "promise", {
value: promiseCapability["[[Promise]]"],
writable: true,
enumerable: true,
configurable: true,
});
Object.defineProperty(obj, "resolve", {
value: promiseCapability["[[Resolve]]"],
writable: true,
enumerable: true,
configurable: true,
});
Object.defineProperty(obj, "reject", {
value: promiseCapability["[[Reject]]"],
writable: true,
enumerable: true,
configurable: true,
});
return obj;
}
Данную операцию можно вызвать так:
withResolvers.call(Promise); /// {promise: Promise, resolve: ƒ, reject: ƒ}
Если вы внимательно просмотрели код Promise.withResolvers на js, то вы заметили что данная функция использует операцию NewPromiseCapability, которая в своей сути и делает всю основную работу по получению необходимых значений, а Promise.withResolvers является лишь оберткой над NewPromiseCapability.
Просто посмотрите на результаты вызовов обеих операций:
NewPromiseCapability(Promise); /// {[[Promise]]: Promise, [[Resolve]]: ƒ, [[Reject]]: ƒ}
withResolvers.call(Promise); /// {promise: Promise, resolve: ƒ, reject: ƒ}
Разницы вообще по сути нет, кроме следующего:
- NewPromiseCapability - недоступна из коробки (и вряд ли когда будет доступна, так как это внутренняя операция), ее нужно реализовывать самостоятельно, если вам надо
- Promise.withResolvers - слишком свежая и без полифилов ее лучше не использовать
Вот такие дела.
Поддержка данной обертки составляет скудные ~64%, что полностью убивает ее использование без полифила. Если вам нужно закрыть дыру до 90% и больше, то предлагаю использовать вышеизложенные функции в своем коде со следующей строчкой:
Promise.withResolvers || Object.defineProperty(Promise, "withResolvers", {
value: withResolvers,
writable: true,
configurable: true,
});