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); }); } })}