Promise 类核心逻辑
- Promise 局势一个类,在执行这个类的时候,需要传递一个执行器进去,执行器会立即执行
- Promise 中有三种状态分别为
- 等待 pending
- 成功 fulfilled
- 失败 rejected
- resove 和 reject 函数是用来更改状态的
- resolve: fulfilled
- reject: rejected
- then 方法内部就是在判断状态,如果状态是成功,调用成功的回调,否则调用失败的回调。then 方法是被定义到原型对象中的方法
- then 成功回调返回参数表示成功之行之后的结果,如果状态是失败,调用失败的原因应当返回
同步 promise 实现
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
executor(this.resolve, this.reject);
}
resolve(data) {
if (this.status === STATUS.PENDING) {
this.status = STATUS.FULLFILLED;
this.value = data;
}
}
reject(reason) {
if (this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
}
}
then(successCallback, failCallback) {
switch (this.status) {
case STATUS.FULLFILLED:
successCallback(this.value);
break;
case STATUS.REJECTED:
failCallback(this.reason);
break;
default:
break;
}
}
}
module.exports = MyPromise;
多次异步 promise 实现
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
this.successCallback = [];
this.failCallback = [];
executor(this.resolve, this.reject);
}
resolve(data) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.FULLFILLED;
this.value = data;
while (this.successCallback[0]) {
this.successCallback.shift()(this.value);
}
}
reject(reason) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.REJECTED;
this.reason = reason;
if (this.failCallback[0]) {
this.failCallback.shift()(this.reason);
}
}
then(successCallback, failCallback) {
switch (this.status) {
case STATUS.FULLFILLED:
successCallback(this.value);
break;
case STATUS.REJECTED:
failCallback(this.reason);
break;
default:
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
break;
}
}
}
module.exports = MyPromise;
then 方法链式调用
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
this.successCallback = [];
this.failCallback = [];
executor(this.resolve, this.reject);
}
resolve(data) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.FULLFILLED;
this.value = data;
while (this.successCallback[0]) {
this.successCallback.shift()(this.value);
}
}
reject(reason) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.REJECTED;
this.reason = reason;
if (this.failCallback[0]) {
this.failCallback.shift()(this.reason);
}
}
then(successCallback, failCallback) {
const nextPromise = new MyPromise((resolve, reject) => {
switch (this.status) {
case STATUS.FULLFILLED: {
const x = successCallback(this.value);
resolvePromise(x, resolve, reject);
break;
}
case STATUS.REJECTED: {
failCallback(this.reason);
break;
}
default:
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
break;
}
});
return nextPromise;
}
}
function resolvePromise(x, resolve, reject) {
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
module.exports = MyPromise;
避免循环调用 promise
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
this.successCallback = [];
this.failCallback = [];
executor(this.resolve, this.reject);
}
resolve(data) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.FULLFILLED;
this.value = data;
while (this.successCallback[0]) {
this.successCallback.shift()(this.value);
}
}
reject(reason) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.REJECTED;
this.reason = reason;
if (this.failCallback[0]) {
this.failCallback.shift()(this.reason);
}
}
then(successCallback, failCallback) {
const nextPromise = new MyPromise((resolve, reject) => {
switch (this.status) {
case STATUS.FULLFILLED: {
setTimeout(() => {
const x = successCallback(this.value);
resolvePromise(nextPromise, x, resolve, reject);
}, 0);
break;
}
case STATUS.REJECTED: {
failCallback(this.reason);
break;
}
default:
this.successCallback.push(successCallback);
this.failCallback.push(failCallback);
break;
}
});
return nextPromise;
}
}
function resolvePromise(nextPromise, x, resolve, reject) {
if (x === nextPromise) {
reject(new TypeError('A promise cannot be resolved with itself.'));
return;
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
module.exports = MyPromise;
捕获错误和异步模式处理
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
this.successCallback = [];
this.failCallback = [];
try {
executor(this.resolve, this.reject);
} catch (e) {
this.reject(e);
}
}
resolve(data) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.FULLFILLED;
this.value = data;
while (this.successCallback[0]) {
this.successCallback.shift()(this.value);
}
}
reject(reason) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.REJECTED;
this.reason = reason;
if (this.failCallback[0]) {
this.failCallback.shift()(this.reason);
}
}
then(successCallback, failCallback) {
const nextPromise = new MyPromise((resolve, reject) => {
switch (this.status) {
case STATUS.FULLFILLED: {
thenCallback(successCallback, this.value, nextPromise, resolve, reject);
break;
}
case STATUS.REJECTED: {
thenCallback(failCallback, this.reason, nextPromise, resolve, reject);
break;
}
default:
this.successCallback.push(() => {
thenCallback(successCallback, this.value, nextPromise, resolve, reject);
});
this.failCallback.push(() => {
thenCallback(failCallback, this.reason, nextPromise, resolve, reject);
});
break;
}
});
return nextPromise;
}
}
function resolvePromise(nextPromise, x, resolve, reject) {
if (x === nextPromise) {
reject(new TypeError('A promise cannot be resolved with itself.'));
return;
}
if (x instanceof MyPromise) {
x.then(resolve, reject);
} else {
resolve(x);
}
}
function thenCallback(callback, callbackData, nextPromise, resolve, reject) {
setTimeout(() => {
try {
const x = callback(callbackData);
resolvePromise(nextPromise, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
}
module.exports = MyPromise;
回调函数的默认值
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
this.successCallback = [];
this.failCallback = [];
try {
executor(this.resolve, this.reject);
} catch (e) {
this.reject(e);
}
}
resolve(data) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.FULLFILLED;
this.value = data;
while (this.successCallback[0]) {
this.successCallback.shift()(this.value);
}
}
reject(reason) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.REJECTED;
this.reason = reason;
if (this.failCallback[0]) {
this.failCallback.shift()(this.reason);
}
}
then(
successCallback = value => value,
failCallback = reason => {
throw reason;
},
) {
const nextPromise = new MyPromise((resolve, reject) => {
switch (this.status) {
case STATUS.FULLFILLED: {
thenCallback(successCallback(this.value), nextPromise, resolve, reject);
break;
}
case STATUS.REJECTED: {
thenCallback(failCallback(this.reason), nextPromise, resolve, reject);
break;
}
default:
this.successCallback.push(() => {
thenCallback(successCallback(this.value), nextPromise, resolve, reject);
});
this.failCallback.push(() => {
thenCallback(failCallback(this.reason), nextPromise, resolve, reject);
});
break;
}
});
return nextPromise;
}
}
function thenCallback(returnValue, nextPromise, resolve, reject) {
setTimeout(() => {
try {
if (returnValue === nextPromise) {
reject(new TypeError('A promise cannot be resolved with itself.'));
return;
}
if (returnValue instanceof MyPromise) {
returnValue.then(resolve, reject);
} else {
resolve(returnValue);
}
} catch (error) {
reject(error);
}
}, 0);
}
module.exports = MyPromise;
Promise 的 all 和 race 方法
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
this.successCallback = [];
this.failCallback = [];
try {
executor(this.resolve, this.reject);
} catch (e) {
this.reject(e);
}
}
static race(array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i += 1) {
const task = array[i];
if (task instanceof MyPromise) {
task.then(resolve, reject);
} else {
resolve(task);
}
}
});
}
static all(array) {
let index = 0;
const result = [];
return new MyPromise((resolve, reject) => {
function addData(key, value) {
result[key] = value;
index += 1;
if (index === array.length) {
resolve(result);
}
}
for (let i = 0; i < array.length; i += 1) {
const task = array[i];
if (task instanceof MyPromise) {
task.then(
value => addData(i, value),
reason => reject(reason),
);
} else {
addData(i, array[i]);
}
}
});
}
resolve(data) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.FULLFILLED;
this.value = data;
while (this.successCallback[0]) {
this.successCallback.shift()(this.value);
}
}
reject(reason) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.REJECTED;
this.reason = reason;
if (this.failCallback[0]) {
this.failCallback.shift()(this.reason);
}
}
then(
successCallback = value => value,
failCallback = reason => {
throw reason;
},
) {
const nextPromise = new MyPromise((resolve, reject) => {
switch (this.status) {
case STATUS.FULLFILLED: {
thenCallback(successCallback(this.value), nextPromise, resolve, reject);
break;
}
case STATUS.REJECTED: {
thenCallback(failCallback(this.reason), nextPromise, resolve, reject);
break;
}
default:
this.successCallback.push(() => {
thenCallback(successCallback(this.value), nextPromise, resolve, reject);
});
this.failCallback.push(() => {
thenCallback(failCallback(this.reason), nextPromise, resolve, reject);
});
break;
}
});
return nextPromise;
}
}
function thenCallback(returnValue, nextPromise, resolve, reject) {
setTimeout(() => {
try {
if (returnValue === nextPromise) {
reject(new TypeError('A promise cannot be resolved with itself.'));
return;
}
if (returnValue instanceof MyPromise) {
returnValue.then(resolve, reject);
} else {
resolve(returnValue);
}
} catch (error) {
reject(error);
}
}, 0);
}
module.exports = MyPromise;
Finally 方法
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
this.finally = this.finally.bind(this);
this.successCallback = [];
this.failCallback = [];
try {
executor(this.resolve, this.reject);
} catch (e) {
this.reject(e);
}
}
static resolve(data) {
return new MyPromise((resolveCall, reject) => {
if (data instanceof MyPromise) {
data.then(resolveCall, reject);
} else {
resolveCall(data);
}
});
}
static reject(data) {
return new MyPromise((resolve, rejectCall) => {
if (data instanceof MyPromise) {
data.then(resolve, rejectCall);
} else {
rejectCall(data);
}
});
}
static race(array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i += 1) {
const task = array[i];
if (task instanceof MyPromise) {
task.then(resolve, reject);
} else {
resolve(task);
}
}
});
}
static all(array) {
let index = 0;
const result = [];
return new MyPromise((resolve, reject) => {
function addData(key, value) {
result[key] = value;
index += 1;
if (index === array.length) {
resolve(result);
}
}
for (let i = 0; i < array.length; i += 1) {
const task = array[i];
if (task instanceof MyPromise) {
task.then(
value => addData(i, value),
reason => reject(reason),
);
} else {
addData(i, array[i]);
}
}
});
}
resolve(data) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.FULLFILLED;
this.value = data;
while (this.successCallback[0]) {
this.successCallback.shift()(this.value);
}
}
reject(reason) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.REJECTED;
this.reason = reason;
if (this.failCallback[0]) {
this.failCallback.shift()(this.reason);
}
}
then(
successCallback = value => value,
failCallback = reason => {
throw reason;
},
) {
const nextPromise = new MyPromise((resolve, reject) => {
switch (this.status) {
case STATUS.FULLFILLED: {
thenCallback(successCallback(this.value), nextPromise, resolve, reject);
break;
}
case STATUS.REJECTED: {
thenCallback(failCallback(this.reason), nextPromise, resolve, reject);
break;
}
default:
this.successCallback.push(() => {
thenCallback(successCallback(this.value), nextPromise, resolve, reject);
});
this.failCallback.push(() => {
thenCallback(failCallback(this.reason), nextPromise, resolve, reject);
});
break;
}
});
return nextPromise;
}
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason => MyPromise.resolve(callback()).then(() => {
throw reason;
}),
);
}
}
function thenCallback(returnValue, nextPromise, resolve, reject) {
setTimeout(() => {
try {
if (returnValue === nextPromise) {
reject(new TypeError('A promise cannot be resolved with itself.'));
return;
}
if (returnValue instanceof MyPromise) {
returnValue.then(resolve, reject);
} else {
resolve(returnValue);
}
} catch (error) {
reject(error);
}
}, 0);
}
module.exports = MyPromise;
catch 方法
const STATUS = {
PENDING: 'pending',
FULLFILLED: 'fulfilled',
REJECTED: 'rejected',
};
class MyPromise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.resolve = this.resolve.bind(this);
this.reject = this.reject.bind(this);
this.then = this.then.bind(this);
this.finally = this.finally.bind(this);
this.catch = this.catch.bind(this);
this.successCallback = [];
this.failCallback = [];
try {
executor(this.resolve, this.reject);
} catch (e) {
this.reject(e);
}
}
static resolve(data) {
return new MyPromise((resolveCall, reject) => {
if (data instanceof MyPromise) {
data.then(resolveCall, reject);
} else {
resolveCall(data);
}
});
}
static reject(data) {
return new MyPromise((resolve, rejectCall) => {
if (data instanceof MyPromise) {
data.then(resolve, rejectCall);
} else {
rejectCall(data);
}
});
}
static race(array) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i += 1) {
const task = array[i];
if (task instanceof MyPromise) {
task.then(resolve, reject);
} else {
resolve(task);
}
}
});
}
static all(array) {
let index = 0;
const result = [];
return new MyPromise((resolve, reject) => {
function addData(key, value) {
result[key] = value;
index += 1;
if (index === array.length) {
resolve(result);
}
}
for (let i = 0; i < array.length; i += 1) {
const task = array[i];
if (task instanceof MyPromise) {
task.then(
value => addData(i, value),
reason => reject(reason),
);
} else {
addData(i, array[i]);
}
}
});
}
resolve(data) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.FULLFILLED;
this.value = data;
while (this.successCallback[0]) {
this.successCallback.shift()(this.value);
}
}
reject(reason) {
if (this.status !== STATUS.PENDING) {
return;
}
this.status = STATUS.REJECTED;
this.reason = reason;
if (this.failCallback[0]) {
this.failCallback.shift()(this.reason);
}
}
then(
successCallback = value => value,
failCallback = reason => {
throw reason;
},
) {
const nextPromise = new MyPromise((resolve, reject) => {
switch (this.status) {
case STATUS.FULLFILLED: {
thenCallback(successCallback(this.value), nextPromise, resolve, reject);
break;
}
case STATUS.REJECTED: {
thenCallback(failCallback(this.reason), nextPromise, resolve, reject);
break;
}
default:
this.successCallback.push(() => {
thenCallback(successCallback(this.value), nextPromise, resolve, reject);
});
this.failCallback.push(() => {
thenCallback(failCallback(this.reason), nextPromise, resolve, reject);
});
break;
}
});
return nextPromise;
}
finally(callback) {
return this.then(
value => MyPromise.resolve(callback()).then(() => value),
reason =>
MyPromise.resolve(callback()).then(() => {
throw reason;
}),
);
}
catch(failCallback) {
this.then(undefined, failCallback);
}
}
function thenCallback(returnValue, nextPromise, resolve, reject) {
setTimeout(() => {
try {
if (returnValue === nextPromise) {
reject(new TypeError('A promise cannot be resolved with itself.'));
return;
}
if (returnValue instanceof MyPromise) {
returnValue.then(resolve, reject);
} else {
resolve(returnValue);
}
} catch (error) {
reject(error);
}
}, 0);
}
module.exports = MyPromise;