Vladislav Rastoropov ad0109d8f5 deob
2023-03-05 20:00:06 +03:00

189 lines
4.9 KiB
JavaScript

const { _NATIVE_TOSTRING_ } = require('./../utils/constants');
const definePromise = (window) => {
class PromiseNodeJS {
constructor(executor) {
this.state = "pending";
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value) {
if (this.state === "pending") {
debugger;
this.state = "fulfilled";
this.value = value;
this.onFulfilledCallbacks.forEach((callback) => callback(this.value));
}
}
reject(reason) {
if (this.state === "pending") {
this.state = "rejected";
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => callback(this.reason));
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (error) => {
throw error;
};
const promise = new PromiseNodeJS((resolve, reject) => {
if (this.state === "fulfilled") {
setTimeout(() => {
try {
const result = onFulfilled(window, this.value);
PromiseNodeJS.resolvePromise(promise, result, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === "rejected") {
setTimeout(() => {
try {
const result = onRejected(window, this.reason);
PromiseNodeJS.resolvePromise(promise, result, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
} else if (this.state === "pending") {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let result;
if (_NATIVE_TOSTRING_.call(onFulfilled).includes('callContext')) {
result = onFulfilled(window, this.value);
} else {
result = onFulfilled(this.value);
}
PromiseNodeJS.resolvePromise(promise, result, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const result = onRejected(window, this.reason);
PromiseNodeJS.resolvePromise(promise, result, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
});
}
});
return promise;
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(value) {
return new PromiseNodeJS((resolve) => resolve(value));
}
static reject(reason) {
return new PromiseNodeJS((resolve, reject) => reject(reason));
}
static all(promises) {
return new PromiseNodeJS((resolve, reject) => {
debugger;
const results = [];
let count = 0;
for (let i = 0; i < promises.length; i++) {
promises[i].then((value) => {
results[i] = value;
count++;
if (count === promises.length) {
resolve(results);
}
}, reject);
}
});
}
static race(promises) {
return new PromiseNodeJS((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
});
}
static resolvePromise(promise, result, resolve, reject) {
if (promise === result) {
reject(new TypeError("Chaining cycle detected"));
return;
}
if (result instanceof PromiseNodeJS) {
result.then(resolve, reject);
return;
}
if (
result !== null &&
(typeof result === "object" || typeof result === "function")
) {
let called = false;
try {
const then = result.then;
if (typeof then === "function") {
then.call(
result,
(value) => {
if (called) return;
called = true;
PromiseNodeJS.resolvePromise(promise, value, resolve, reject);
},
(error) => {
if (called) return;
called = true;
reject(error);
}
);
return;
}
} catch (error) {
if (called) return;
called = true;
reject(error);
return;
}
}
resolve(result);
}
}
window.Promise = PromiseNodeJS;
};
module.exports = definePromise;