promise
在开发中,常常须要用到 promise,promise 具备很多个性,这一次将对 promise 个性进行总结,并从零写一个 promise。
步骤一
-
Promise 特点
- 1,创立时须要传递一个函数,否则会报错
- 2,会给传入的函数设置两个回调函数
- 3,刚创立的 Promise 对象状态是 pending
class MyPromise {constructor(handle) {
// 3,刚创立的 Promise 对象状态是 pending
this.status = "pending";
// 1,创立时须要传递一个函数,否则会报错
if (!this._isFunction(handle)) {throw new Error("请传入一个函数");
}
// 2,会给传入的函数设置两个回调函数
handle(this._resolve.bind(this), this._reject.bind(this))
}
_resolve() {}
_reject() {}
_isFunction(fn) {return typeof fn === "function";}
}
步骤二
-
Promise 特点
- 4,状态一旦产生扭转就不可再次扭转
-
5,能够通过 then 来监听状态的扭转
- 5.1,如果创立监听时,状态曾经扭转,立刻执行监听回调
- 5.2,如果创立监听时,状态未扭转,会等状态扭转后执行
- 5.3,同一 promise 对象能够增加多个 then 监听,状态扭转时依照注册程序顺次执行
// 定义常量保留对象的状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class MyPromise {constructor(handle) {
// 3,刚创立的 Promise 对象状态是 pending
this.status = PENDING;
// 胜利回调的值
this.value = undefined;
// 失败回调的值
this.reason = undefined;
// 注册的胜利回调
this.onResolvedCallbacks = [];
// 注册的失败回调
this.onRejectedCallbacks = [];
// 1,创立时须要传递一个函数,否则会报错
if (!this._isFunction(handle)) {throw new Error("请传入一个函数");
}
// 2,会给传入的函数设置两个回调函数
handle(this._resolve.bind(this), this._reject.bind(this))
}
_resolve(value) {
// 4,状态一旦产生扭转就不可再次扭转
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 5.3,同一 promise 对象能够增加多个 then 监听,状态扭转时依照注册程序顺次执行
this.onResolvedCallbacks.forEach(fn => fn(this.value));
}
}
_reject(reason) {
// 4,状态一旦产生扭转就不可再次扭转
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 5.3,同一 promise 对象能够增加多个 then 监听,状态扭转时依照注册程序顺次执行
this.onRejectedCallbacks.forEach(fn => fn(this.reason));
}
}
then(onResolved, onRejected) {
// 判断有没有传入胜利的回调
if (this._isFunction(onResolved)) {
// 5.1,如果创立监听时,状态曾经扭转,立刻执行监听回调
if (this.status === FULFILLED) {onResolved(this.value);
}
}
// 判断有没有传入失败的回调
if (this._isFunction(onRejected)) {
// 5.1,如果创立监听时,状态曾经扭转,立刻执行监听回调
if (this.status === REJECTED) {onRejected(this.reason);
}
}
// 5.2,如果创立监听时,状态未扭转,会等状态扭转后执行
if (this.status === PENDING) {if (this._isFunction(onResolved)) {this.onResolvedCallbacks.push(onResolved);
}
if (this._isFunction(onRejected)) {this.onRejectedCallbacks.push(onRejected);
}
}
}
_isFunction(fn) {return typeof fn === "function";}
}
参考 前端手写面试题具体解答
详解 then 办法
- 接管两个参数:胜利回调,失败回调
- 如果 promise 失败了,然而没有注册失败监听,就会报错
-
then 办法每次执行结束都会返回一个新的 Promise 对象
-
如果 then 办法只有胜利回调
- 则它返回的 promise 的状态会继承以后 promise 的状态。
- 如果以后 promise 的状态为胜利:新 promise 的值为以后 then 的胜利回调的返回值。
- 如果以后 promise 的状态为失败:新的 promise 没有失败监听,则会报错
- 如果 then 办法同时蕴含胜利回调、失败回调
- 则它返回的 promise 的状态都为胜利,且值为胜利或者失败回调的返回值。
-
-
回调函数的返回值
-
如果 then 办法的胜利 / 失败回调返回的是 promise 对象
- 则 then 办法返回的新的 promise 对象的状态由新 promise 的外部决定。
- 且值为新 promise 的内 resolve/reject 函数传递的参数。
-
如果 then 办法的胜利 / 失败回调返回的是一般数据类型
- 则 then 办法返回的新的 promise 对象的状态都为胜利。
- 且值为胜利 / 失败回调的返回值,即都会传递给新的 promise 对象胜利的回调。
-
如果 then 办法的胜利 / 失败回调没有返回值
- 同返回一般数据类型
-
-
失败回调函数
- 能够捕捉上一个 promise 对象的 then 办法中胜利回调函数执行时的异样
then(onResolved, onRejected) {return new MyPromise((nextResolve, nextReject) => {
// 1. 判断有没有传入胜利的回调
if (this._isFunction(onResolved)) {
// 2. 判断以后的状态是否是胜利状态
if (this.status === FULFILLED) {
try {
// 拿到上一个 promise 胜利回调执行的后果
let result = onResolved(this.value);
// console.log("result", result);
// 判断执行的后果是否是一个 promise 对象
if (result instanceof MyPromise) {result.then(nextResolve, nextReject);
} else {
// 将上一个 promise 胜利回调执行的后果传递给下一个 promise 胜利的回调
nextResolve(result);
}
} catch (e) {nextReject(e);
}
}
}
// 1. 判断有没有传入失败的回调
// if(this._isFunction(onRejected)){
try {
// 2. 判断以后的状态是否是失败状态
if (this.status === REJECTED) {let result = onRejected(this.reason);
if (result instanceof MyPromise) {result.then(nextResolve, nextReject);
} else {nextResolve(result);
}
}
} catch (e) {nextReject(e);
}
// }
// 2. 判断以后的状态是否是默认状态
if (this.status === PENDING) {if (this._isFunction(onResolved)) {
// this.onResolvedCallback = onResolved;
this.onResolvedCallbacks.push(() => {
try {let result = onResolved(this.value);
if (result instanceof MyPromise) {result.then(nextResolve, nextReject);
} else {nextResolve(result);
}
} catch (e) {nextReject(e);
}
});
}
// if(this._isFunction(onRejected)){
// this.onRejectedCallback = onRejected;
this.onRejectedCallbacks.push(() => {
try {let result = onRejected(this.reason);
if (result instanceof MyPromise) {result.then(nextResolve, nextReject);
} else {nextResolve(result);
nextReject();}
} catch (e) {nextReject(e);
}
});
// }
}
});
}
详解 catch 办法
- 其实是 then 办法的失败回调函数的语法糖
- 如果须要同时应用 then 和 catch 办法,必须应用链式编程,不然会报错
- 能够捕捉上一个 promise 对象的 then 办法中胜利回调函数执行时的异样
catch(onRejected) {return this.then(undefined, onRejected);
}
为啥应用 catch 时最好应用链式编程
- 因为 then 办法只有胜利回调,所以 p2 的状态会继承 p1
- 又因为 p2 的状态为失败,且没有对 p2 进行失败监听,所以报错
let p1 = new Promise(function (resolve, reject) {// resolve();
reject();});
let p2 = p1.then(function () {console.log("胜利");
});
p1.catch(function () {console.log("失败 1");
});
Promise.all()
-
Promise.all(params) 特点
- 参数为一个数组,且数组元素为 promise 类型数据
-
返回值为一个 promise,
-
如果所有 promise 都执行胜利
- 返回值为所有 promise 都胜利时返回的后果的汇合
- 如果有一个 promise 执行失败了,则返回失败的 promise
-
static all(list){return new MyPromise(function (resolve, reject) {let arr = [];
let count = 0;
for(let i = 0; i < list.length; i++){let p = list[i];
p.then(function (value) {// arr.push(value); 留神不要这样写,会导致后果程序不对
arr[i] = value
count++;
if(list.length === count){resolve(arr);
}
}).catch(function (e) {reject(e);
});
}
});
}
Promise.race()
-
Promise.race(params) 特点
- 参数为一个数组,且数组元素为 promise 类型数据
- 返回值为一个 promise,且返回值为第一个胜利或者失败的 promise 的值
static race(list){return new MyPromise(function (resolve, reject) {for(let p of list){p.then(function (value) {resolve(value);
}).catch(function (e) {reject(e);
});
}
})
}