promise
js
/**
* 术语
* “promise” 是一个对象或函数,其 then 方法的行为符合本规范。
* “thenable” 是定义 then 方法的对象或函数。
* “value” 是任何合法的 JavaScript 值(包括undefined、thenable 或 promise)。
* “异常” 是使用 throw 语句抛出的值。
* “reason” 是一个值,表示承诺被拒绝的原因。
*/
const PENDING = '待定状态';
const RESOLVED = '已完成状态';
const REJECTED = '已拒绝状态';
const noop = (v) => v;
const noopErr = (e) => {
throw e;
};
const isFn = (v) => typeof v === 'function';
const isObj = (v) => typeof v === 'object';
class Promise {
constructor(callback) {
this.value = undefined; // 任何合法的 JavaScript 值(包括undefined、thenable 或 promise)。
this.reason = undefined; // 一个值,表示承诺被拒绝的原因。
this.status = PENDING; // 当未决时,承诺:待定
this.resolvedFnList = []; // 已完成状态的回调函数列表
this.rejectedFnList = []; // 已拒绝状态的回调函数列表
const resolve = (value) => {
if (this.status === PENDING) {
this.status = RESOLVED;
this.value = value;
this.resolvedFnList.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.rejectedFnList.forEach((fn) => fn());
}
};
try {
callback(resolve, reject); // 主函数立即执行
} catch (error) {
reject(error);
}
}
static resolve(v) {
return v instanceof Promise ? v : new Promise((res, rej) => res(v));
}
static reject(v) {
return v instanceof Promise ? v : new Promise((res, rej) => rej(v));
}
static all(arr) {}
static race(arr) {}
then(onResolved, onRejected) {}
catch(onCatchFn) {
this.then(undefined, onCatchFn);
}
/**
* 不管成功还是失败,都会走到 finally 中,
* 并且 finally 之后,还可以继续 then。并且会将值原封不动的传递给后面的 then.
*/
finally(callback) {
const resolve = (value) => {
const res = callback();
return Promise.resolve(res).then(() => value);
};
const reject = (reason) => {
const res = callback();
return Promise.resolve(res).then(() => {
throw reason;
});
};
return this.then(resolve, reject);
}
}
/**
* 术语
* “promise” 是一个对象或函数,其 then 方法的行为符合本规范。
* “thenable” 是定义 then 方法的对象或函数。
* “value” 是任何合法的 JavaScript 值(包括undefined、thenable 或 promise)。
* “异常” 是使用 throw 语句抛出的值。
* “reason” 是一个值,表示承诺被拒绝的原因。
*/
const PENDING = '待定状态';
const RESOLVED = '已完成状态';
const REJECTED = '已拒绝状态';
const noop = (v) => v;
const noopErr = (e) => {
throw e;
};
const isFn = (v) => typeof v === 'function';
const isObj = (v) => typeof v === 'object';
class Promise {
constructor(callback) {
this.value = undefined; // 任何合法的 JavaScript 值(包括undefined、thenable 或 promise)。
this.reason = undefined; // 一个值,表示承诺被拒绝的原因。
this.status = PENDING; // 当未决时,承诺:待定
this.resolvedFnList = []; // 已完成状态的回调函数列表
this.rejectedFnList = []; // 已拒绝状态的回调函数列表
const resolve = (value) => {
if (this.status === PENDING) {
this.status = RESOLVED;
this.value = value;
this.resolvedFnList.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.rejectedFnList.forEach((fn) => fn());
}
};
try {
callback(resolve, reject); // 主函数立即执行
} catch (error) {
reject(error);
}
}
static resolve(v) {
return v instanceof Promise ? v : new Promise((res, rej) => res(v));
}
static reject(v) {
return v instanceof Promise ? v : new Promise((res, rej) => rej(v));
}
static all(arr) {}
static race(arr) {}
then(onResolved, onRejected) {}
catch(onCatchFn) {
this.then(undefined, onCatchFn);
}
/**
* 不管成功还是失败,都会走到 finally 中,
* 并且 finally 之后,还可以继续 then。并且会将值原封不动的传递给后面的 then.
*/
finally(callback) {
const resolve = (value) => {
const res = callback();
return Promise.resolve(res).then(() => value);
};
const reject = (reason) => {
const res = callback();
return Promise.resolve(res).then(() => {
throw reason;
});
};
return this.then(resolve, reject);
}
}
js
// Promise.all(iterable)
// Promise.all 等待所有兑现(或第一个拒绝)的结果。
function all(arr = []) {
return new Promise((resolve, reject) => {
let resolveList = [];
let resolveCount = 0;
function insertResolveList(idx, val) {
resolveList[idx] = val;
resolveCount++;
if (resolveCount === arr.length) resolve(resolveList);
}
arr.forEach((obj, idx) => {
if (obj instanceof Promise) {
obj.then(
(val) => insertResolveList(idx, val), // 收集 resolve 结果
(err) => reject(err) // 直接输出 reject 结果
);
} else {
insertResolveList(idx, val); // 原始值,收集原始值
}
});
});
}
// Promise.all(iterable)
// Promise.all 等待所有兑现(或第一个拒绝)的结果。
function all(arr = []) {
return new Promise((resolve, reject) => {
let resolveList = [];
let resolveCount = 0;
function insertResolveList(idx, val) {
resolveList[idx] = val;
resolveCount++;
if (resolveCount === arr.length) resolve(resolveList);
}
arr.forEach((obj, idx) => {
if (obj instanceof Promise) {
obj.then(
(val) => insertResolveList(idx, val), // 收集 resolve 结果
(err) => reject(err) // 直接输出 reject 结果
);
} else {
insertResolveList(idx, val); // 原始值,收集原始值
}
});
});
}
js
// Promise.race(iterable)
// Promise.race 等待第一个兑现的结果。
function race(arr) {
return new Promise((resolve, reject) => {
// 是否存在 Promise 子项
let hasPromise = false;
arr.forEach((obj, idx) => {
if (obj instanceof Promise) {
hasPromise = true;
// 先到先得
obj.then(resolve, reject);
}
// 没有 Promise 子项,返回第一个子项
if (idx === arr.length - 1 && !hasPromise) {
resolve(arr[0]);
}
});
});
}
// Promise.race(iterable)
// Promise.race 等待第一个兑现的结果。
function race(arr) {
return new Promise((resolve, reject) => {
// 是否存在 Promise 子项
let hasPromise = false;
arr.forEach((obj, idx) => {
if (obj instanceof Promise) {
hasPromise = true;
// 先到先得
obj.then(resolve, reject);
}
// 没有 Promise 子项,返回第一个子项
if (idx === arr.length - 1 && !hasPromise) {
resolve(arr[0]);
}
});
});
}
js
const noop = (v) => v;
const noopErr = (e) => {
throw e;
};
const isFn = (v) => typeof v === 'function';
const isObj = (v) => typeof v === 'object';
const PENDING = '待定状态';
const RESOLVED = '已完成状态';
const REJECTED = '已拒绝状态';
function then(onResolved, onRejected) {
// onResolved 可选,可能是 Promise、fn 等,非函数忽略,使用 noop 函数 向下传递 value
onResolved = isFn(onResolved) ? onResolved : noop;
// onRejected 可选,可能是 Promise、fn 等,非函数忽略,使用 noopErr 函数向下传递 reason
onRejected = isFn(onRejected) ? onRejected : noopErr;
// 承诺解决程序
const resolvePromise = (promise2, x, resolve, reject) => {
// 如果 promise 和 x 引用同一个对象,以 TypeError 为理由拒绝。
if (promise2 === x) return reject(new TypeError('TypeError'));
// 2.3.3.3.3 如果同时调用resolvePromise和rejectPromise,或者多次调用同一个参数,则第一个调用优先,任何进一步的调用都将被忽略。
let called = false;
// 2.3.3 如果 x 是一个非 null 的对象或函数
if ((isObj(x) && x !== null) || isFn(x)) {
try {
// 3.5
// 这个首先存储对 的引用x.then,然后测试该引用,然后调用该引用的过程避免了对该x.then属性的多次访问。
// 这些预防措施对于确保访问器属性的一致性很重要,访问器属性的值可能会在检索之间发生变化。
let then = x.then;
if (isFn(then)) {
then.call(
x,
(y) => {
if (called) return;
called = true;
// 递归( 可能promise 嵌套)
resolvePromise(promise2, y, resolve, reject);
},
(z) => {
if (called) return; // 只要失败就失败
called = true;
reject(z);
}
);
} else {
// 2.3.3.4 如果 then 不是一个函数,用 x 完成 promise。
resolve(x);
}
} catch (e) {
// 2.3.3.2 抛出的异常的结果 e,e 作为拒绝 promise 的原因。
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
};
const promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
queueMicrotask(() => {
try {
let x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.status === REJECTED) {
queueMicrotask(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.status === PENDING) {
this.resolvedFnList.push(() => {
queueMicrotask(() => {
try {
let x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
this.rejectedFnList.push(() => {
queueMicrotask(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
});
// 2.2.7 then必须返回一个承诺
return promise2;
}
const noop = (v) => v;
const noopErr = (e) => {
throw e;
};
const isFn = (v) => typeof v === 'function';
const isObj = (v) => typeof v === 'object';
const PENDING = '待定状态';
const RESOLVED = '已完成状态';
const REJECTED = '已拒绝状态';
function then(onResolved, onRejected) {
// onResolved 可选,可能是 Promise、fn 等,非函数忽略,使用 noop 函数 向下传递 value
onResolved = isFn(onResolved) ? onResolved : noop;
// onRejected 可选,可能是 Promise、fn 等,非函数忽略,使用 noopErr 函数向下传递 reason
onRejected = isFn(onRejected) ? onRejected : noopErr;
// 承诺解决程序
const resolvePromise = (promise2, x, resolve, reject) => {
// 如果 promise 和 x 引用同一个对象,以 TypeError 为理由拒绝。
if (promise2 === x) return reject(new TypeError('TypeError'));
// 2.3.3.3.3 如果同时调用resolvePromise和rejectPromise,或者多次调用同一个参数,则第一个调用优先,任何进一步的调用都将被忽略。
let called = false;
// 2.3.3 如果 x 是一个非 null 的对象或函数
if ((isObj(x) && x !== null) || isFn(x)) {
try {
// 3.5
// 这个首先存储对 的引用x.then,然后测试该引用,然后调用该引用的过程避免了对该x.then属性的多次访问。
// 这些预防措施对于确保访问器属性的一致性很重要,访问器属性的值可能会在检索之间发生变化。
let then = x.then;
if (isFn(then)) {
then.call(
x,
(y) => {
if (called) return;
called = true;
// 递归( 可能promise 嵌套)
resolvePromise(promise2, y, resolve, reject);
},
(z) => {
if (called) return; // 只要失败就失败
called = true;
reject(z);
}
);
} else {
// 2.3.3.4 如果 then 不是一个函数,用 x 完成 promise。
resolve(x);
}
} catch (e) {
// 2.3.3.2 抛出的异常的结果 e,e 作为拒绝 promise 的原因。
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
};
const promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
queueMicrotask(() => {
try {
let x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.status === REJECTED) {
queueMicrotask(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.status === PENDING) {
this.resolvedFnList.push(() => {
queueMicrotask(() => {
try {
let x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
this.rejectedFnList.push(() => {
queueMicrotask(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
});
// 2.2.7 then必须返回一个承诺
return promise2;
}
js
/**
* 术语
* “promise” 是一个对象或函数,其 then 方法的行为符合本规范。
* “thenable” 是定义 then 方法的对象或函数。
* “value” 是任何合法的 JavaScript 值(包括undefined、thenable 或 promise)。
* “异常” 是使用 throw 语句抛出的值。
* “reason” 是一个值,表示承诺被拒绝的原因。
*/
const PENDING = '待定状态';
const RESOLVED = '已完成状态';
const REJECTED = '已拒绝状态';
const noop = (v) => v;
const noopErr = (e) => {
throw e;
};
const isFn = (v) => typeof v === 'function';
const isObj = (v) => typeof v === 'object';
class Promise {
constructor(callback) {
this.value = undefined; // 任何合法的 JavaScript 值(包括undefined、thenable 或 promise)。
this.reason = undefined; // 一个值,表示承诺被拒绝的原因。
this.status = PENDING; // 当未决时,承诺:待定
this.resolvedFnList = []; // 已完成状态的回调函数列表
this.rejectedFnList = []; // 已拒绝状态的回调函数列表
const resolve = (value) => {
// 2.1.1.1 可以转换到已完成或拒绝状态。
// 2.1.2.1 实现时,承诺:不得过渡到任何其他状态。
if (this.status === PENDING) {
this.status = RESOLVED;
this.value = value;
this.resolvedFnList.forEach((fn) => fn());
}
};
const reject = (reason) => {
// 2.1.1.1 可以转换到已完成或拒绝状态。
// 2.1.3.1 当被拒绝时,一个承诺:不得过渡到任何其他状态。
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.rejectedFnList.forEach((fn) => fn());
}
};
try {
callback(resolve, reject); // 主函数立即执行
} catch (error) {
reject(error);
}
}
/**
* 承诺必须提供一种then方法来访问其当前或最终值或原因。
* 一个 promise 的then方法接受两个参数:onResolve onRejected
* 2.2.1 这两个 onResolved 和 onRejected 可选的参数:
* 2.2.1.1 如果 onResolved 不是函数,则必须忽略它。
* 2.2.1.2 如果 onRejected 不是函数,则必须忽略它。
*
* 始终返回一个 Promise 对象
* onResolved 可选,可能是 Promise、fn 等,非函数忽略,使用 noop 函数 向下传递 value
* onRejected 可选,可能是 Promise、fn 等,非函数忽略,使用 noopErr 函数向下传递 reason
* (先抛出 err,后续捕获 err,如果没有捕获到,最终抛出 err)
* then 可以链式调用,可以多次调用
* 当已拒绝状态时,没有找到处理拒绝状态的回调函数前都是已拒绝状态,找到后返回的新的 Promise 对象为已完成状态。
*/
then(onResolved, onRejected) {
// onResolved 可选,可能是 Promise、fn 等,非函数忽略,使用 noop 函数 向下传递 value
onResolved = isFn(onResolved) ? onResolved : noop;
// onRejected 可选,可能是 Promise、fn 等,非函数忽略,使用 noopErr 函数向下传递 reason
onRejected = isFn(onRejected) ? onRejected : noopErr;
// 承诺解决程序
const resolvePromise = (promise2, x, resolve, reject) => {
// 如果 promise 和 x 引用同一个对象,以 TypeError 为理由拒绝。
if (promise2 === x) return reject(new TypeError('TypeError'));
// 2.3.3.3.3 如果同时调用resolvePromise和rejectPromise,或者多次调用同一个参数,则第一个调用优先,任何进一步的调用都将被忽略。
let called = false;
// 2.3.3 如果 x 是一个非 null 的对象或函数
if ((isObj(x) && x !== null) || isFn(x)) {
try {
// 3.5
// 这个首先存储对 的引用x.then,然后测试该引用,然后调用该引用的过程避免了对该x.then属性的多次访问。
// 这些预防措施对于确保访问器属性的一致性很重要,访问器属性的值可能会在检索之间发生变化。
let then = x.then;
if (isFn(then)) {
then.call(
x,
(y) => {
if (called) return;
called = true;
// 递归( 可能promise 嵌套)
resolvePromise(promise2, y, resolve, reject);
},
(z) => {
if (called) return; // 只要失败就失败
called = true;
reject(z);
}
);
} else {
// 2.3.3.4 如果 then 不是一个函数,用 x 完成 promise。
resolve(x);
}
} catch (e) {
// 2.3.3.2 抛出的异常的结果 e,e 作为拒绝 promise 的原因。
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
};
const promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === PENDING) {
this.resolvedFnList.push(() => {
setTimeout(() => {
try {
let x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.rejectedFnList.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
// 2.2.7 then必须返回一个承诺
return promise2;
}
/**
* resolve 静态方法,返回一个已完成 Promise 对象
* resolve 可以没有接收函数,不报错
*/
static resolve(v) {
return v instanceof Promise ? v : new Promise((res, rej) => res(v));
}
/**
* reject 静态方法,返回一个已拒绝 Promise 对象
* reject 返回的一个已拒绝 Promise 对象,必须要找到处理方法(catch() 或者 then.onRejected()),否则报错
*/
static reject(v) {
return v instanceof Promise ? v : new Promise((res, rej) => rej(v));
}
/**
* all 方法是一个静态方法
* all 方法返回一个Promise对象
* all 方法传入的是一个带有 Promise 对象的数组
* 只有数组中的 Promise 对象都成功执行,才能回调成功方法
* 如果有 Promise 对象失败,则调用失败方法
*/
static all(arr) {
return new Promise((resolve, reject) => {
const resultArr = [];
let count = 0;
function insertArr(idx, val) {
resultArr[idx] = val;
count++;
if (count === arr.length) resolve(resultArr);
}
arr.forEach((obj, idx) => {
if (obj instanceof Promise) {
obj.then(
(val) => insertArr(idx, val),
(err) => reject(err)
);
} else {
insertArr(idx, val);
}
});
});
}
/**
* race 方法传入 Promise 对象数组。
* race 只返回执行最快的一个 Promise 结果,不论成功与失败。
* 返回结果与最快的 Promise 的成功与失败保持一致。
* 如果数组不包含 Promise 对象,返回数组第一项
*/
static race(arr) {
return new Promise((resolve, reject) => {
let hasPromise = false;
arr.forEach((obj, idx) => {
if (obj instanceof Promise) {
hasPromise = true;
obj.then(resolve, reject);
}
if (idx === arr.length - 1 && !hasPromise) {
resolve(arr[0]);
}
});
});
}
/**
* 不管成功还是失败,都会走到 finally 中,
* 并且 finally 之后,还可以继续 then。并且会将值原封不动的传递给后面的 then.
*/
finally(callback) {
return this.then(
(value) => {
return Promise.resolve(callback()).then(() => {
return value;
});
},
(reason) => {
return Promise.resolve(callback()).then(() => {
throw reason;
});
}
);
}
/**
* catch 是一个 then 的已拒绝状态。
* catch 不能想 then 一样自动接受 Promise 对象的状态
* catch 接受异常错误和未处理过的拒绝状态的返回数据
*/
catch(onCatchFn) {
this.then(undefined, onCatchFn);
}
}
// Promise/A+规范提供了一个专门的测试脚本,可以测试所编写的代码是否符合Promise/A+的规范。
// 首先,在 promise2 实现的代码中,增加以下代码:
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
// module.exports = Promise;
/**
* 测试方法 (测试范围不包括 Promise 方法)
* > npm i -g promises-aplus-tests
* > promises-aplus-tests demo.js
*
* 测试结果:872 passing (17s)
*/
/**
* 术语
* “promise” 是一个对象或函数,其 then 方法的行为符合本规范。
* “thenable” 是定义 then 方法的对象或函数。
* “value” 是任何合法的 JavaScript 值(包括undefined、thenable 或 promise)。
* “异常” 是使用 throw 语句抛出的值。
* “reason” 是一个值,表示承诺被拒绝的原因。
*/
const PENDING = '待定状态';
const RESOLVED = '已完成状态';
const REJECTED = '已拒绝状态';
const noop = (v) => v;
const noopErr = (e) => {
throw e;
};
const isFn = (v) => typeof v === 'function';
const isObj = (v) => typeof v === 'object';
class Promise {
constructor(callback) {
this.value = undefined; // 任何合法的 JavaScript 值(包括undefined、thenable 或 promise)。
this.reason = undefined; // 一个值,表示承诺被拒绝的原因。
this.status = PENDING; // 当未决时,承诺:待定
this.resolvedFnList = []; // 已完成状态的回调函数列表
this.rejectedFnList = []; // 已拒绝状态的回调函数列表
const resolve = (value) => {
// 2.1.1.1 可以转换到已完成或拒绝状态。
// 2.1.2.1 实现时,承诺:不得过渡到任何其他状态。
if (this.status === PENDING) {
this.status = RESOLVED;
this.value = value;
this.resolvedFnList.forEach((fn) => fn());
}
};
const reject = (reason) => {
// 2.1.1.1 可以转换到已完成或拒绝状态。
// 2.1.3.1 当被拒绝时,一个承诺:不得过渡到任何其他状态。
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.rejectedFnList.forEach((fn) => fn());
}
};
try {
callback(resolve, reject); // 主函数立即执行
} catch (error) {
reject(error);
}
}
/**
* 承诺必须提供一种then方法来访问其当前或最终值或原因。
* 一个 promise 的then方法接受两个参数:onResolve onRejected
* 2.2.1 这两个 onResolved 和 onRejected 可选的参数:
* 2.2.1.1 如果 onResolved 不是函数,则必须忽略它。
* 2.2.1.2 如果 onRejected 不是函数,则必须忽略它。
*
* 始终返回一个 Promise 对象
* onResolved 可选,可能是 Promise、fn 等,非函数忽略,使用 noop 函数 向下传递 value
* onRejected 可选,可能是 Promise、fn 等,非函数忽略,使用 noopErr 函数向下传递 reason
* (先抛出 err,后续捕获 err,如果没有捕获到,最终抛出 err)
* then 可以链式调用,可以多次调用
* 当已拒绝状态时,没有找到处理拒绝状态的回调函数前都是已拒绝状态,找到后返回的新的 Promise 对象为已完成状态。
*/
then(onResolved, onRejected) {
// onResolved 可选,可能是 Promise、fn 等,非函数忽略,使用 noop 函数 向下传递 value
onResolved = isFn(onResolved) ? onResolved : noop;
// onRejected 可选,可能是 Promise、fn 等,非函数忽略,使用 noopErr 函数向下传递 reason
onRejected = isFn(onRejected) ? onRejected : noopErr;
// 承诺解决程序
const resolvePromise = (promise2, x, resolve, reject) => {
// 如果 promise 和 x 引用同一个对象,以 TypeError 为理由拒绝。
if (promise2 === x) return reject(new TypeError('TypeError'));
// 2.3.3.3.3 如果同时调用resolvePromise和rejectPromise,或者多次调用同一个参数,则第一个调用优先,任何进一步的调用都将被忽略。
let called = false;
// 2.3.3 如果 x 是一个非 null 的对象或函数
if ((isObj(x) && x !== null) || isFn(x)) {
try {
// 3.5
// 这个首先存储对 的引用x.then,然后测试该引用,然后调用该引用的过程避免了对该x.then属性的多次访问。
// 这些预防措施对于确保访问器属性的一致性很重要,访问器属性的值可能会在检索之间发生变化。
let then = x.then;
if (isFn(then)) {
then.call(
x,
(y) => {
if (called) return;
called = true;
// 递归( 可能promise 嵌套)
resolvePromise(promise2, y, resolve, reject);
},
(z) => {
if (called) return; // 只要失败就失败
called = true;
reject(z);
}
);
} else {
// 2.3.3.4 如果 then 不是一个函数,用 x 完成 promise。
resolve(x);
}
} catch (e) {
// 2.3.3.2 抛出的异常的结果 e,e 作为拒绝 promise 的原因。
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
};
const promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
setTimeout(() => {
try {
let x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === PENDING) {
this.resolvedFnList.push(() => {
setTimeout(() => {
try {
let x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.rejectedFnList.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
// 2.2.7 then必须返回一个承诺
return promise2;
}
/**
* resolve 静态方法,返回一个已完成 Promise 对象
* resolve 可以没有接收函数,不报错
*/
static resolve(v) {
return v instanceof Promise ? v : new Promise((res, rej) => res(v));
}
/**
* reject 静态方法,返回一个已拒绝 Promise 对象
* reject 返回的一个已拒绝 Promise 对象,必须要找到处理方法(catch() 或者 then.onRejected()),否则报错
*/
static reject(v) {
return v instanceof Promise ? v : new Promise((res, rej) => rej(v));
}
/**
* all 方法是一个静态方法
* all 方法返回一个Promise对象
* all 方法传入的是一个带有 Promise 对象的数组
* 只有数组中的 Promise 对象都成功执行,才能回调成功方法
* 如果有 Promise 对象失败,则调用失败方法
*/
static all(arr) {
return new Promise((resolve, reject) => {
const resultArr = [];
let count = 0;
function insertArr(idx, val) {
resultArr[idx] = val;
count++;
if (count === arr.length) resolve(resultArr);
}
arr.forEach((obj, idx) => {
if (obj instanceof Promise) {
obj.then(
(val) => insertArr(idx, val),
(err) => reject(err)
);
} else {
insertArr(idx, val);
}
});
});
}
/**
* race 方法传入 Promise 对象数组。
* race 只返回执行最快的一个 Promise 结果,不论成功与失败。
* 返回结果与最快的 Promise 的成功与失败保持一致。
* 如果数组不包含 Promise 对象,返回数组第一项
*/
static race(arr) {
return new Promise((resolve, reject) => {
let hasPromise = false;
arr.forEach((obj, idx) => {
if (obj instanceof Promise) {
hasPromise = true;
obj.then(resolve, reject);
}
if (idx === arr.length - 1 && !hasPromise) {
resolve(arr[0]);
}
});
});
}
/**
* 不管成功还是失败,都会走到 finally 中,
* 并且 finally 之后,还可以继续 then。并且会将值原封不动的传递给后面的 then.
*/
finally(callback) {
return this.then(
(value) => {
return Promise.resolve(callback()).then(() => {
return value;
});
},
(reason) => {
return Promise.resolve(callback()).then(() => {
throw reason;
});
}
);
}
/**
* catch 是一个 then 的已拒绝状态。
* catch 不能想 then 一样自动接受 Promise 对象的状态
* catch 接受异常错误和未处理过的拒绝状态的返回数据
*/
catch(onCatchFn) {
this.then(undefined, onCatchFn);
}
}
// Promise/A+规范提供了一个专门的测试脚本,可以测试所编写的代码是否符合Promise/A+的规范。
// 首先,在 promise2 实现的代码中,增加以下代码:
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
// module.exports = Promise;
/**
* 测试方法 (测试范围不包括 Promise 方法)
* > npm i -g promises-aplus-tests
* > promises-aplus-tests demo.js
*
* 测试结果:872 passing (17s)
*/
js
// 并发请求限制
function limitRequst(list, limit) {
// 返回一个 Promise
return new Promise((resolve) => {
let pending = 0; // 待定状态任务数量
let resultList = new Array(list.length); // 任务结果
let taskList = list.map((task, index) => ({ index, task })); // 任务列表(记录任务索引,用以保证任务结果顺序)
request();
function request() {
const subList = taskList.splice(0, limit - pending); // 提取待处理任务
const subListPatched = patch(subList); // 修补待处理任务
pending += subListPatched.length; // 更新待定状态任务数量
// 并发任务
Promise.allSettled(subListPatched).then((resList) => {
// 收集任务结果 (保持原始顺序)
resList.forEach((res, idx) => {
const index = subList[idx].index;
resultList[index] = res;
});
// 结果全部完成判定,并返回任务结果
if (!resultList.includes(undefined)) {
resolve(resultList);
}
});
}
// 修补待处理任务
function patch(list = []) {
return list.map(({ task }) => {
// 非正常任务修补
if (task instanceof Promise === false) {
task = Promise.resolve(task); // 修补
}
// 捕获单任务的最终状态
task.finally(() => {
pending--; // 更新待定状态任务数量
request(); // 处理剩余任务
}).catch(() => {
// 您的 Promise 必须自己处理 catch 情况,
// 此处 catch 只是为了保证方法能正常运行,但对 catch 结果不做处理。
});
return task;
});
}
});
}
function createPromise() {
return new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
setTimeout(() => {
resolve('resolve');
}, 500);
} else {
setTimeout(() => {
reject(new Error('reject'));
}, 500);
}
});
}
const list = [createPromise(), createPromise(), 1, createPromise(), createPromise(), null];
limitRequst(list, 3).then((list) => {
console.log('list', list.length, list);
});
// 控制台输出:
// list 6 [
// { status: 'fulfilled', value: 'resolve' },
// {
// status: 'rejected',
// reason: Error: reject
// at Timeout._onTimeout (/Users/pch/Documents/GitHub/test.js:65:24)
// at listOnTimeout (node:internal/timers:559:17)
// at processTimers (node:internal/timers:502:7)
// },
// { status: 'fulfilled', value: 1 },
// { status: 'fulfilled', value: 'resolve' },
// {
// status: 'rejected',
// reason: Error: reject
// at Timeout._onTimeout (/Users/pch/Documents/GitHub/test.js:65:24)
// at listOnTimeout (node:internal/timers:559:17)
// at processTimers (node:internal/timers:502:7)
// },
// { status: 'fulfilled', value: null }
// ]
// 并发请求限制
function limitRequst(list, limit) {
// 返回一个 Promise
return new Promise((resolve) => {
let pending = 0; // 待定状态任务数量
let resultList = new Array(list.length); // 任务结果
let taskList = list.map((task, index) => ({ index, task })); // 任务列表(记录任务索引,用以保证任务结果顺序)
request();
function request() {
const subList = taskList.splice(0, limit - pending); // 提取待处理任务
const subListPatched = patch(subList); // 修补待处理任务
pending += subListPatched.length; // 更新待定状态任务数量
// 并发任务
Promise.allSettled(subListPatched).then((resList) => {
// 收集任务结果 (保持原始顺序)
resList.forEach((res, idx) => {
const index = subList[idx].index;
resultList[index] = res;
});
// 结果全部完成判定,并返回任务结果
if (!resultList.includes(undefined)) {
resolve(resultList);
}
});
}
// 修补待处理任务
function patch(list = []) {
return list.map(({ task }) => {
// 非正常任务修补
if (task instanceof Promise === false) {
task = Promise.resolve(task); // 修补
}
// 捕获单任务的最终状态
task.finally(() => {
pending--; // 更新待定状态任务数量
request(); // 处理剩余任务
}).catch(() => {
// 您的 Promise 必须自己处理 catch 情况,
// 此处 catch 只是为了保证方法能正常运行,但对 catch 结果不做处理。
});
return task;
});
}
});
}
function createPromise() {
return new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
setTimeout(() => {
resolve('resolve');
}, 500);
} else {
setTimeout(() => {
reject(new Error('reject'));
}, 500);
}
});
}
const list = [createPromise(), createPromise(), 1, createPromise(), createPromise(), null];
limitRequst(list, 3).then((list) => {
console.log('list', list.length, list);
});
// 控制台输出:
// list 6 [
// { status: 'fulfilled', value: 'resolve' },
// {
// status: 'rejected',
// reason: Error: reject
// at Timeout._onTimeout (/Users/pch/Documents/GitHub/test.js:65:24)
// at listOnTimeout (node:internal/timers:559:17)
// at processTimers (node:internal/timers:502:7)
// },
// { status: 'fulfilled', value: 1 },
// { status: 'fulfilled', value: 'resolve' },
// {
// status: 'rejected',
// reason: Error: reject
// at Timeout._onTimeout (/Users/pch/Documents/GitHub/test.js:65:24)
// at listOnTimeout (node:internal/timers:559:17)
// at processTimers (node:internal/timers:502:7)
// },
// { status: 'fulfilled', value: null }
// ]