Appearance
promise
什么是 promise
- Promise 是一种在 JavaScript 中提供了异步编程范式的特殊对象。它可以被用来表示一个将来会发生的操作,或者说它是一个代表一个异步操作结果。使用它,可以轻松地实现异步请求,并用非常方便的方式处理请求成功或失败之后的操作
promise 优缺点
- 优:promise 很好的解决了异步编程中的,回调层层嵌套问题,使代码结构看起来更加的简洁,可读性更强
- 缺:promise 一旦开始,无法取消或重置,意味着犯错了无法挽回
promiseA+规范
- 所有的 promise 都会遵循一个 promiseA+规范来实现promiseA+文档
1、promise 执行器
- promise 是一个类,当在实例化时,会立马执行构造器,构造器接受 resolve, reject 函数等待用户执行
WARNING
构造器在执行的时候如果出现异常直接会调用 reject 函数
js
class Promise {
constructor(executor) {
const resolve = (value) => {
console.log(value);
};
const reject = (reason) => {
console.log(reason);
};
try {
// 出现异常直接走reject
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
}
new Promise((resolve, reject) => {
resolve("ok");
});
new Promise((resolve, reject) => {
throw "error";
resolve("ok");
});
2、promise 状态
- promise 有种状态分别是
pending(等待)
、fufilled(成功)
、rejected(失败)
- 状态只能从
pending=>fufilled
或者pending=>rejected
不能逆转 - 当在执行构造器中的
resolve
或者reject
时,如果此时的状态是 pending,改变当前的状态,并且把成功或者失败的回调值
存储在实例上
js
const STATUS = {
PENDING: "PENDING",
FUFILLED: "FUFILLED",
REJECTED: "REJECTED",
};
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
const resolve = (value) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = value;
}
};
const reject = (reason) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
}
new Promise((resolve, reject) => {
resolve("ok");
});
new Promise((resolve, reject) => {
reject("error");
});
3、then 函数
- 1、then 接收 2 个回调函数(onFulfilled,onRejected),一个成功的回调,一个失败的回调
- 2、当 then 回调传递的不是函数时,为了能够把值传递下去,会转换成函数
- 3、当在调用 then 函数时,如果此次时的状态是 pending(等待),会把成功、失败的回调加入到队列中,等待执行
- 4、如果此时的状态不是 pending(等待),会直接调用成功或者失败的回调
js
const STATUS = {
PENDING: "PENDING",
FUFILLED: "FUFILLED",
REJECTED: "REJECTED",
};
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((onRejected) => {
onRejected(this.value);
});
}
};
const reject = (reason) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((onRejected) => {
onRejected(this.value);
});
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw err;
};
if (this.status === STATUS.PENDING) {
this.onFulfilledCallbacks.push(() => onFulfilled);
this.onRejectedCallbacks.push(() => onRejected);
} else if (this.status === STATUS.FUFILLED) {
onFulfilled(this.value);
} else {
onRejected(this.reason);
}
}
}
let promise = new Promise((resolve, reject) => {
resolve("ok");
});
promise.then((value) => {
console.log(value);
});
new Promise((resolve, reject) => {
reject("error");
});
4、then 函数链式调用
- 为了支持 then 能够链式调用,then 函数会返回一个新的 promise2
js
then ( onFulfilled, onRejected ) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : ( value ) => value
onRejected = typeof onRejected === 'function' ? onRejected : ( err ) => { throw err };
const promise2 = new Promise( ( resolve, reject ) => {
if ( this.status === STATUS.PENDING ) {
this.onFulfilledCallbacks.push( () => onFulfilled )
this.onRejectedCallbacks.push( () => onRejected )
} else if ( this.status === STATUS.FUFILLED ) {
onFulfilled( this.value )
} else {
onRejected( this.reason )
}
} )
return promise2
}
5、then 函数回调返回值处理
- 如果 then 回调函数调用出现异常,会走到下一个失败的 then 回调中
- 如果 then 回调返回的是一个 promise,promise 成功或者失败,会走到下一个成功或者失败的 then 回调中
- 如果 then 回调返回的是一个普通的值,不管是成功或者失败的回调,都有走到下一个成功的 then 回调中
循环引用案例
js
// 循环引用案例:
const promise2 = new Promise((resolve, reject) => {
resolve("ok");
});
// 循环引用,造成无限死循环需要处理成 reject失败
promise2.then(() => {
return promise2;
});
// 处理异常
if (promise2 === x) {
return reject(new TypeError("循环引用,造成无限死循环"));
}
// ....
then 回调返回值是对象,取 then 异常处理
js
const x = {};
Object.defineProperty(x, "then", {
get() {
throw new Error("error");
},
});
// 处理异常
try {
const then = x.then;
} catch (e) {
// 取then错误走下一个失败的then回调
reject(e);
}
// ....
如果 then 回调返回值是一个 Promise,并且 resolve 中的值也是一个 Promise,需要递归把值传递下去
js
const promise = new Promise((resolve, reject) => {
resolve("ok");
});
promise.then(() => {
return new Promise((resolve, reject) => {
resolve(
Promise((resolve, reject) => {
resolve("ok");
})
);
});
});
// 处理递归
then.call(
x,
(y) => {
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},
(r) => {
// promise失败直接到下一个失败的then回调
reject(r);
}
);
// ....
如果 then 回调返回值是不一个规范的 Promise,即可以成功也可以失败,我们需要防止这种情况,不可以逆向
js
const promise = new Promise((resolve, reject) => {
resolve("ok");
});
promise.then(() => {
// 自己实现的Promise即可以成功也可以失败
return new MyPromise((resolve, reject) => {
resolve("ok");
reject("err");
});
});
// 处理不规范的Promise(即可以成功也可以失败)
let called;
try {
const then = x.then;
if (typeof then === "function") {
// 执行promise.then
then.call(
x,
(y) => {
if (called) return;
called = true;
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},
(r) => {
if (called) return;
called = true;
// promise失败直接到下一个失败的then回调
reject(r);
}
);
} else {
if (called) return;
called = true;
// 普通值走下一个成功的then回调
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
// 取then错误走下一个失败的then回调
reject(e);
}
// ....
6、完整源码实现
js
const STATUS = {
PENDING: "PENDING",
FUFILLED: "FUFILLED",
REJECTED: "REJECTED",
};
/**
*
* @param {*} x then回调的返回值
* @param {*} promise promise2的实例
* @param {*} resolve promise成功
* @param {*} reject promise失败
*/
function resolvePromise(x, promise2, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError("循环引用,造成无限死循环"));
}
// 对象或者function都有可能是Promise
if ((typeof x === "object" && x !== null) || typeof x === "function") {
// 防止别人实现的promise即可以成功,也可以失败
let called;
try {
const then = x.then;
if (typeof then === "function") {
// 执行promise.then
then.call(
x,
(y) => {
if (called) return;
called = true;
// y有可能还是一个promise,递归到普通值结束
resolvePromise(y, promise2, resolve, reject);
},
(r) => {
if (called) return;
called = true;
// promise失败直接到下一个失败的then回调
reject(r);
}
);
} else {
if (called) return;
called = true;
// 普通值走下一个成功的then回调
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
// 取then错误走下一个失败的then回调
reject(e);
}
} else {
// 普通值走下一个成功的then回调
resolve(x);
}
}
class Promise {
constructor(executor) {
this.status = STATUS.PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.FUFILLED;
this.value = value;
this.onFulfilledCallbacks.forEach((onRejected) => {
onRejected(value);
});
}
};
const reject = (reason) => {
if (this.status === STATUS.PENDING) {
this.status = STATUS.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((onRejected) => {
onRejected(reason);
});
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw err;
};
const promise2 = new Promise((resolve, reject) => {
if (this.status === STATUS.PENDING) {
this.onFulfilledCallbacks.push(() => {
// 保证promise2实例化完成
setTimeout(() => {
try {
const x = onFulfilled(this.value);
// 处理回调的结果
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
// then回调出新异常直接调用下一个失败的then
reject(e);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
});
});
} else if (this.status === STATUS.FUFILLED) {
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
});
} else {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(x, promise2, resolve, reject);
} catch (e) {
reject(e);
}
});
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(val) {
return new Promise((resolve) => {
resolve(val);
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
static all(promisArr) {
return new Promise((resolve, reject) => {
let result = [],
count = 0;
function done(i, data) {
result[i] = data;
if (count++ == i) {
resolve(result);
}
}
promisArr.map((p, i) => {
p.then((data) => done(i, data), reject);
});
});
}
static race(promisArr) {
return new Promise((resolve, reject) => {
promisArr.map((p) => {
p.then((data) => resolve(data), reject);
});
});
}
}
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = Promise;
6、case
- 安装
npm install promises-aplus-tests -g
- 执行
promises-aplus-tests promise.js
(promise 入口文件路径)
then 交替执行
- 如果有多个 fulfilled 状态的 promise 实例,同时执行 then 链式调用,
then 会交替调用
- 这是编译器的优化,防止一个 promise 持续占据事件
js
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(4);
});
Promise.resolve()
.then(() => {
console.log(10);
})
.then(() => {
console.log(20);
})
.then(() => {
console.log(30);
})
.then(() => {
console.log(40);
});
Promise.resolve()
.then(() => {
console.log(100);
})
.then(() => {
console.log(200);
})
.then(() => {
console.log(300);
})
.then(() => {
console.log(400);
});
// 1 10 100 2 20 200 3 30 300 4 40 400
then 返回 promise
js
Promise.resolve()
.then(() => {
console.log(0);
return Promise.resolve(4); // 相当于多处一个 promise 实例,会慢2拍
})
.then((res) => {
console.log(res);
});
Promise.resolve()
.then(() => {
console.log(1);
})
.then(() => {
console.log(2);
})
.then(() => {
console.log(3);
})
.then(() => {
console.log(5);
})
.then(() => {
console.log(6);
});
// 0 1 2 3 4 5 6