Promise A+ 规范与 JavaScript Promise 对象的关系
Promise A+ 规范是一个抽象的规范,它定义了Promise对象应该如何行为,以及它们应该如何与其他异步操作交互。这个规范并没有指定Promise对象的具体实现细节,而是提供了一套通用的接口和行为模式,使得任何遵循该规范的实现都能够互相兼容。
JavaScript Promise对象是Promise A+ 规范的一个具体实现。在JavaScript中,Promise对象提供了一种编写异步代码的方式,允许您以一种更加清晰和结构化的方式处理异步操作的结果。JavaScript的Promise对象遵循Promise A+规范,这意味着它们实现了规范中定义的所有要求,包括构造函数、resolve
、reject
、then
、catch
、all
和race
方法。
Promise A+ 规范
Promise 所需要具备的方法:
- new Promise((resolve,reject)=>{}) , 构造函数需要传入一个 fn , 并且 fn 执行时需要传入 resolve & reject 。
- Promise.resolve(value) , Promise.constructor 中有一个 resolve 方法, 需要将 value 值返回到 then 中 。
- Promise.reject(err) , 与 Promise.reject 类似。
- then , 对 fullfiled 状态的回调处理
- catch , 对 rejected 状态的回调处理
- Promise.all(promiseArray) , 对所有 Promise 状态都改变时进行处理
- Promise.race(promiseArray) , 当有一个 Promise 状态发生改变时进行处理
- 构造函数中需要 state 标识状态 , value 存储 fullfiled 的返回值 , reason 存储失败原因
详细规范传送门Promises/A+ (promisesaplus.com)
自己实现 Promise
Promise 类基本结构
根据 PromiseA+ 规范的定义我们可以大致建立以下的实现结构。
js
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class Promise{
constructor(fn){
this.state = PENDING;
this.value = null;
this.reason = null;
this.fulfilledHandlers = [];
this.rejectedHandlers = [];
const resolve = ()=>{};
const reject = ()=>{};
try{
fn(resolve,reject)
}catch(err){
reject(error)
}
}
static resolve(){}
static reject(){}
static all(){}
static race(){}
then(){}
catch(){}
}
resolve , reject 实现
resolve , reject 需要改变 state 并且异步执行 then catch 的回调
js
const resolve = val => {
setTimeout(() => {
if (_this.state === PENDING) {
_this.value = val;
_this.state = FULFILLED;
_this.resolveHandlers.forEach(cb =>{
try {
cb(val);
}catch(e){
reject(e);
}
});
}
}, 0);
};
const reject = err => {
setTimeout(() => {
if (_this.state === PENDING) {
_this.reason = err;
_this.state = REJECTED;
_this.rejectedHandlers.map(cb => {
try {
cb(err);
}catch(e){
reject(e);
}
});
}
}, 0);
};
Promise.resolve = val => {
if (val instanceof Promise) {
return val.then(resolve, reject);
}
return resolve(val);
};
then catch 实现
then catch 返回一个 Promise 类型, 将状态的回调 push 到数组中 , 使用
promise.then().then(res=>{console.log(res)})
的方式时,第一个 then 需要再次传递 onFulfilled 的值。
js
Promise.prototype.then = (onFulfilled, onRejected) => {
var _this = this;
var resolveHandler, rejectHandler;
if (typeof onFulfilled === "function") {
resolveHandler = onFulfilled;
}
resolveHandler = val => val;
rejectHandler =
typeof onRejected === "function"
? onRejected
: err => {
throw err;
};
if (_this.state === PENDING) {
_this.resolveHandlers.push(onFulfilled);
_this.rejectedHandlers.push(onRejected);
return;
}
return new Promise((resolve, reject) => {
if (_this.state === FULFILLED) {
resolve(_this.value);
}else{
reject(_this.reason)
}
});
};
全量代码
js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
constructor(executor) {
this.state = PENDING;
this.value = null;
this.reason = null;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === PENDING) {
this.state = FULFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === 'function'
? onRejected
: (err) => {
throw err;
};
let promise2 = new MyPromise((resolve, reject) => {
if (this.state === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.state === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.state === PENDING) {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
});
return promise2;
}
catch(errCallback) {
return this.then(null, errCallback);
}
resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(
x,
(y) => {
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
(err) => {
if (called) return;
called = true;
reject(err);
}
);
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
static resolve(value) {
return value instanceof MyPromise
? value
: new MyPromise((resolve) => resolve(value));
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
static all(promiseArr) {
let result = [];
let promiseCount = 0;
return new MyPromise((resolve, reject) => {
promiseArr.forEach((promise, i) => {
MyPromise.resolve(promise).then(
(val) => {
result[i] = val;
promiseCount++;
if (promiseCount === promiseArr.length) {
resolve(result);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
static race(promiseArr) {
return new MyPromise((resolve, reject) => {
promiseArr.forEach((promise, i) => {
MyPromise.resolve(promise).then(
(val) => {
resolve(val);
},
(reason) => {
reject(reason);
}
);
});
});
}
}
测试用例
js
// 1. 测试 Promise.resolve
let promise1 = MyPromise.resolve(3);
promise1.then((value) => console.log(value)); // 应该打印出 3
// 2. 测试 Promise.reject
let promise2 = MyPromise.reject('Error occurred');
promise2.catch((reason) => console.log(reason)); // 应该打印出 "Error occurred"
// 3. 测试 MyPromise.then 和异步
let promise3 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('Hello');
}, 1000);
});
promise3.then((value) => console.log(value)); // 隔1秒后应该打印出 "Hello"
// 4. 测试 catch 错误处理
let promise4 = new MyPromise((resolve, reject) => {
throw new Error('some error');
});
promise4.catch((error) => console.log(error.toString())); // 应该打印出 "Error: some error"
// 5. 测试 Promise.all
let promise5 = MyPromise.all([
Promise.resolve(4),
Promise.resolve(5),
Promise.resolve(6),
]);
promise5.then((values) => console.log(values)); // 应打印出 [4, 5, 6]
// 6. 测试 Promise.race
let promise6 = MyPromise.race([
MyPromise.resolve(7),
MyPromise.reject('Error'),
MyPromise.resolve(8),
]);
promise6.then((value) => console.log(value)); // 应打印出 7
//7.
let promise7 = new MyPromise((resolve, reject) => {
resolve('promise7')
});
promise7.then((value) =>{
console.log(value)
return MyPromise.resolve('promise7 ppp')
}).then(val=>console.log(val)); // 隔1秒后应该打印出 "Hello"
总结
异步编程是JavaScript中处理非阻塞操作的关键,它允许程序在等待某些操作(如网络请求、文件读写等)完成时继续执行其他任务。Promise对象的引入,解决了传统回调函数(callback)可能带来的"回调地狱"问题,通过链式调用和更好的错误处理机制,使得异步流程控制变得更加直观和易于管理。