共计 5360 个字符,预计需要花费 14 分钟才能阅读完成。
Promise 从入门到精通
概念
Promise 是 ES6 引入的进行异步编程的新的解决方案
备注:旧计划是单纯的应用回调函数
- 从语法上来说:它就是一个构造函数,
- 从性能上来说:能够封装异步的工作,并且能够对后果进行解决
Promise 最大的益处:能够解决回调天堂的问题,并且它在指定回调和错误处理这一块更加的灵便与不便
回调天堂的典型情景:
异步编程有哪些?
答:fs 文件操作、数据库操作、AJAX、定时器等等
为什么要应用 Promise?
-
指定回调函数的形式更加灵便
旧的形式:必须在启动异步工作前指定·promise:启动异步工作 => 返回 promise 对象 => 给 promise 对象绑定回调函数(甚至能够在异步工作完结后指定多个回调)
-
反对链式调用,能够解决回调天堂问题
回调天堂的毛病:1)不便于浏览;2)不便于异样解决
Promise 的根本流程
promise 的状态扭转
状态指的是 promise 实例中的一个属性:【PromiseState】
pending 未决定的
fulfilled 胜利
rejected 失败
1. pending => fulfilled
2. pending => rejected
promise 对象的状态只有这两种扭转,1 个 promise 对象的状态只能扭转一次,
不可能由 fulfilled 转 rejected
也不可能由 rejected 转 fulfilled
promise 对象后果值属性介绍
实例对象中另一个属性:【PromiseResult】
保留的是胜利 / 失败的后果
resolve 能够批改 PromiseResult 的值
rejected 能够批改 PromiseResult 的值
如何应用 Promise?
API
1.Promise 构造函数:Promise(exector){}
1)exector 函数:称为执行器函数 (resolve,reject)=>{}
2)resolve 函数:是 Promise 外部定义的,胜利时咱们调用 resolve 函数
3)reject 函数:是 Promise 外部定义的,失败时咱们调用 reject 函数
阐明:exector 会在 Promise 外部立刻同步调用,异步操作在执行器中执行
2.Promise.prototype.then 办法:(onResolved,onRejected)=>{}
1)onResolved 函数:指定胜利的回调函数 value=>{}
2)onRejected 函数:指定失败的回调函数 reason=>{}
阐明:指定用于失去胜利 value 的胜利回调和用于失去失败 reason 的失败回调,返回一个新的 promise 对象
3.Promise.prototype.catch 办法:(onRejected)=>{}
onRejected 函数:指定失败的回调函数 reason=>{}
阐明:then()的语法糖,相当于 then(undefined,onRejected)
4.Promise.resolve 办法 (value)=>{}
1)value: 胜利的数据或 promise 对象
阐明:返回一个胜利 / 失败的 promise 对象
作用:为了疾速失去一个 promise 对象,而且可能封装 1 个值,将这个值转化为 promise 对象
如果传入的参数为非 promise 类型的对象,则返回的后果为胜利的 promise 对象
如果传入的参数为 promise 对象,则参数的后果决定了 resolve 的后果
5.Promise.reject 办法:(reason)=>{}
作用:疾速返回一个失败的 promise 对象
返回的后果永远都是失败的 promise 对象
6.Promise.all 办法:(promises 数组)=>{}
参数:蕴含 n 个 promise 的数组
阐明:返回一个新的 promise 对象,只有所有的 promise 都胜利才胜利,只有有一个失败就间接失败
7.Promise.race 办法:(promises 数组)=>{}
race 有赛跑的意思
参数:蕴含 n 个 promise 的数组
阐明:返回一个新的 promise 对象,第一个扭转状态的 promise 就是最终的后果状态
promise 的几个关键问题
1. 如何扭转 promise 的状态?
(1) resolve(value): 如果以后是 pending 就会变为 fulfilled
(2) reject(reason): 如果以后是 pending 就会变为 rejected
(3) 抛出异样: 如果以后是 pending 就会变为 rejected
2. 一个 promise 指定多个胜利 / 失败回调函数, 都会调用吗?
当 promise 扭转为对应状态时都会调用
3. 扭转 promise 状态和指定回调函数谁先谁后?
(1) 都有可能, 失常状况下是先指定回调再扭转状态, 但也能够先改状态再指定回调
(2) 如何先改状态再指定回调?
① 在执行器中间接调用 resolve()/reject()
② 提早更长时间才调用 then()
(3) 什么时候能力失去数据?
① 如果先指定的回调, 那当状态产生扭转时, 回调函数就会调用, 失去数据
② 如果先扭转的状态, 那当指定回调时, 回调函数就会调用, 失去数据
4. promise.then()返回的新 promise 的后果状态由什么决定?
(1) 简略表白: 由 then()指定的回调函数执行的后果决定
(2) 具体表白:
① 如果抛出异样, 新 promise 变为 rejected, reason 为抛出的异样
② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
③ 如果返回的是另一个新 promise, 此 promise 的后果就会成为新 promise 的后果
5. promise 如何串连多个操作工作?
(1) promise 的 then()返回一个新的 promise, 能够开成 then()的链式调用
(2) 通过 then 的链式调用串连多个同步 / 异步工作
let p = new Promise((resolve,reject)=>{setTimeout(()=>{resolve('ok');
},1000);
});
p.then(v=>{return new Promise((resolve,reject)=>{resolve('success');
});
}).then(v=>{console.log(v);
}).then(v=>{console.log(v);
})
6. promise 异样传透?
(1) 当应用 promise 的 then 链式调用时, 能够在最初指定失败的回调,
(2) 后面任何操作出了异样, 都会传到最初失败的回调中解决
let p = new Promise((resolve,reject)=>{reject('err');
});
p.then(v=>{console.log(111);
}).then(v=>{console.log(222);
}).then(v=>{console.log(333);
}).catch(r=>{console.log(r);
});
7. 中断 promise 链?
(1) 当应用 promise 的 then 链式调用时, 在两头中断, 不再调用前面的回调函数
(2) 方法: 在回调函数中返回一个 pendding 状态的 promise 对象
代码展现
// 申明函数 执行器『同步回调』function Promise(executor) {
// 设置实例对象的属性
this.PromiseState = 'pending';
this.PromiseResult = undefined;
this.callbacks = [];
// 申明函数
const success = (value) => {if (this.PromiseState !== 'pending') return;
// 批改状态为胜利 PromiseState
this.PromiseState = 'fulfilled';
// 设置胜利的后果值 PromiseResult
this.PromiseResult = value;
// 调用回调
if (this.callbacks.length > 0) {
this.callbacks.forEach(cbObj => {
// 执行胜利的回调
cbObj.ok();})
}
}
const fail = (reason) => {if (this.PromiseState !== 'pending') return;
// 批改状态为失败 PromiseState
this.PromiseState = 'rejected';
// 设置胜利的后果值 PromiseResult
this.PromiseResult = reason;
// 调用回调
if (this.callbacks.length > 0) {
this.callbacks.forEach(cbObj => {
// 执行胜利的回调
cbObj.ng();})
}
}
try {
// 调用执行器函数
executor(success, fail);
} catch (e) {
// 调用 fail 函数
fail(e);
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
// 判断 异样穿透
if(typeof onRejected !== 'function'){onRejected = reason => {throw reason};
}
// 值传递
if(typeof onFulfilled !== 'function'){onFulfilled = value => value;}
return new Promise((resolve, reject) => {
// 封装函数简化代码
let callback = (type) => {
try {let res = type(this.PromiseResult);
// 判断
if (res instanceof Promise) {
res.then(v => {resolve(v);
}, r => {reject(r);
})
} else {resolve(res);
}
} catch (e) {reject(e);
}
}
// 判断 胜利
if (this.PromiseState === 'fulfilled') {setTimeout(() => {callback(onFulfilled);//
})
}
// 失败
if (this.PromiseState === 'rejected') {setTimeout(() => {callback(onRejected);
})
}
//pending
if (this.PromiseState === 'pending') {
// 保留回调
this.callbacks.push({ok: function () {
// 胜利
callback(onFulfilled);
},
ng: function () {callback(onRejected);
}
})
}
});
}
Promise.prototype.catch = function(onRejected){return this.then(undefined, onRejected);
}
Promise.resolve = function(value){return new Promise((resolve,reject) => {
// 判断
if(value instanceof Promise){//value.then(resolve, reject); 这行代码和上面 5 行代码性能一样
value.then(v=>{resolve(v);
}, r => {reject(r);
});
}else{resolve(value);
}
})
}
Promise.reject = function(reason){return new Promise((resolve, reject) => {reject(reason);
})
}
Promise.all = function (promiseArr) {return new Promise((resolve, reject) => {
let count = 0;
let arr = [];
for (let i = 0; i < promiseArr.length; i++) {promiseArr[i].then(v => {
count++;
arr[i] = v;
if (count === promiseArr.length) {resolve(arr);
}
}, r => {reject(r);
});
}
});
}
Promise.race = function (promiseArr) {return new Promise((resolve, reject) => {
promiseArr.forEach(item => {
item.then(v => {resolve(v);
}, r => {reject(r);
});
});
});
}
面试题 1:
let p = new Promise((resolve, reject) => {reject("error");
});
p.then(v => {console.log(v);
}).then(v => {console.log(v);
}, r => {console.log(r); // error
}).then(v => {console.log(v); // undefined
}, r => {console.warn(r);
});