const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function Promise (executor) {
const self = this;
self.status = PENDING;
self.value = undefined;
self.reason = undefined;
self.onFulfilledCbs = [];//成功的回调
self.onRejectedCbs = []; //失败的回调
/*
PromiseA+
2.1 Promise States
A promise must be in one of three states: pending, fulfilled, or rejected.
2.1.1 When pending, a promise:
2.1.1.1 may transition to either the fulfilled or rejected state.
2.1.2 When fulfilled, a promise:
2.1.2.1 must not transition to any other state.
2.1.2.2 must have a value, which must not change.
2.1.3 When rejected, a promise:
2.1.3.1 must not transition to any other state.
2.1.3.2 must have a reason, which must not change.
*/
function resolve (value) {
if (self.status === PENDING) {
self.status = FULFILLED;
self.value = value;
/*
PromiseA+ 2.2.6
2.2.6 then may be called multiple times on the same promise.
2.2.6.1 If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
*/
self.onFulfilledCbs.forEach(fn => fn());
}
}
function reject (reason) {
if (self.status === PENDING) {
self.status = REJECTED;
self.reason = reason;
/*
PromiseA+ 2.2.6
2.2.6 then may be called multiple times on the same promise.
2.2.6.2 If/when promise is rejected, all respective onRejected callbacks must execute in the order of their originating calls to then.
*/
self.onRejectedCbs.forEach(fn => fn());
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
/*
PromiseA+ 2.2.1
2.2.1 Both onFulfilled and onRejected are optional arguments:
2.2.1.1 If onFulfilled is not a function, it must be ignored.
2.2.1.2 If onRejected is not a function, it must be ignored.
PromiseA+ 2.2.5
2.2.5 onFulfilled and onRejected must be called as functions (i.e. with no this value). [3.2]
PromiseA+ 2.2.7.3
2.2.7.3 If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
PromiseA+ 2.2.7.4
2.2.7.4 If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.
*/
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
const self = this;
/*
PromiseA+ 2.2.7
2.2.7 then must return a promise [3.3].
promise2 = promise1.then(onFulfilled, onRejected);
*/
let promise2 = new Promise((resolve, reject) => {
if (self.status === FULFILLED) {
/*
PromiseA+ 2.2.2
2.2.2 If onFulfilled is a function:
2.2.2.1 it must be called after promise is fulfilled, with promise’s value as its first argument.
2.2.2.2 it must not be called before promise is fulfilled.
2.2.2.3 it must not be called more than once.
PromiseA+ 2.2.4 --- setTimeout
2.2.4 onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].
*/
setTimeout(() => {
try {
/*
PromiseA+ 2.2.7.1
2.2.7.1 If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
*/
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
/*
PromiseA+ 2.2.7.2
2.2.7.2 If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
*/
reject(e);
}
});
}
/*
PromiseA+ 2.2.3
2.2.3 If onRejected is a function,
2.2.3.1 it must be called after promise is rejected, with promise’s reason as its first argument.
2.2.3.2 it must not be called before promise is rejected.
2.2.3.3 it must not be called more than once.
*/
if (self.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (self.status === PENDING) {
self.onFulfilledCbs.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
self.onRejectedCbs.push(() => {
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
});
return promise2;
}
function resolvePromise (promise2, x, resolve, reject) {
/*
PromiseA+ 2.3.1
2.3.1 If promise and x refer to the same object, reject promise with a TypeError as the reason.
*/
if (promise2 === x) {
reject(new TypeError('Chaining cycle'));
}
const self = this;
/*
PromiseA+ 2.3.2
2.3.2 If x is a promise, adopt its state [3.4]:
2.3.2.1 If x is pending, promise must remain pending until x is fulfilled or rejected.
2.3.2.2 If/when x is fulfilled, fulfill promise with the same value.
2.3.2.3 If/when x is rejected, reject promise with the same reason.
PromiseA+ 2.3.3
2.3.3 Otherwise, if x is an object or function,
*/
if (x && typeof x === 'object' || typeof x === 'function') {
/*
PromiseA+ 2.3.3.3.3 只能调用一次
2.3.3.3.3 If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
*/
let used;
try {
/*
PromiseA+ 2.3.3.1
2.3.3.1 Let then be x.then. [3.5]
*/
let then = x.then;
if (typeof then === 'function') {
/*
PromiseA+ 2.3.3.3
2.3.3.3 If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where:
2.3.3.3.1 If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
2.3.3.3.2 If/when rejectPromise is called with a reason r, reject promise with r.
2.3.3.3.3 If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
*/
then.call(x, (y) => {
if (used) return;
used = true;
resolvePromise(promise2, y, resolve, reject);
}, (r) => {
if (used) return;
used = true;
reject(r);
});
} else {
/*
PromiseA+ 2.3.3.4
2.3.3.4 If then is not a function, fulfill promise with x.
*/
if (used) return;
used = true;
resolve(x);
}
} catch (e) {
/*
PromiseA+ 2.3.3.2
2.3.3.2 If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
2.3.3.3.4 If calling then throws an exception e,
2.3.3.3.4.1 If resolvePromise or rejectPromise have been called, ignore it.
2.3.3.3.4.2 Otherwise, reject promise with e as the reason.
*/
if (used) return;
used = true;
reject(e);
}
} else {
/*
PromiseA+ 2.3.3.4
2.3.3.4 If x is not an object or function, fulfill promise with x.
*/
resolve(x);
}
}
/*
用于指定出错时的回调,是特殊的then方法,catch之后,可以继续 .then
*/
Promise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
/*
不管成功还是失败,都会走到finally中,并且finally之后,还可以继续then。并且会将值原封不动的传递给后面的then.
*/
Promise.prototype.finally = function (callback) {
return this.then((value) => {
return Promise.resolve(callback()).then(() => {
return value;
});
}, (err) => {
return Promise.resolve(callback()).then(() => {
throw err;
});
});
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
/**
1 参数是一个 Promise 实例
将不做任何修改、原封不动地返回这个实例。
2 参数是一个thenable对象
方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法,(thenable对象指的是具有then方法的对象)
3 参数不是具有then()方法的对象,或根本就不是对象,或者不带有任何参数
返回一个新的 Promise 对象,value 为传入参数,状态为resolved
*/
Promise.resolve = function (param) {
if (param instanceof Promise) {
return param;
}
return new Promise((resolve, reject) => {
if (param && param.then && typeof param.then === 'function') {
setTimeout(() => {
param.then(resolve, reject);
});
} else {
resolve(param);
}
});
}
/*
Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。
*/
Promise.reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
/*
返回一个promise对象
1 promise 中所有的 promise都“完成”时或参数中不包含 promise 时回调完成。
2 如果参数中有一个promise失败,那么Promise.all返回的promise对象失败
3 在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组
*/
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let index = 0;
let result = [];
if (promises.length === 0) {
resolve(result);
} else {
function processValue (i, data) {
result[i] = data;
if (++index === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
//promises[i] 不一定是promise,可能是普通值
Promise.resolve(promises[i])
.then((data) => {
processValue(i, data);
}, (err) => {
reject(err);
return;
});
}
}
});
}
/*
Promise.race函数返回一个 Promise,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。
1 如果传的参数数组是空,则返回的 promise 将永远等待。
2 如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。
*/
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
if (promises.length === 0) {
return;
} else {
for (let i = 0; i < promises.length; i++) {
Promise.resolve(promises[i]).then((data) => {
resolve(data);
return;
}, (err) => {
reject(err);
return;
});
}
}
});
}
module.exports = Promise;