Promise用法
Promise
Promise有三种状态
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。
- 已拒绝(rejected): 意味着操作失败。
Promise的状态是不可逆的,只有pending -> fulfilled, 或者pending -> rejected,成功或失败后不能改变其状态。
Promise和then是配套出现,then中有两个参数,第一个表示成功,第二个表示失败
new Promise((resolve, reject) => { resolve('成功') // 这是通知执行的作用 reject('失败') // 无效,已经是fulfilled状态了,不能再改变 }).then( msg => {console.log(msg)}, error=>{console.log(error)} )
// 结果: 成功
** 微任务、宏任务混合🌰
console.log(1) new Promise(resolve => { setTimeout(() =>{ resolve(3) }, 0) setTimeout(() => { console.log(5) },0) }).then(result => { console.log(result) }).then(() => { console.log(4) }) console.log(2)
执行结果 1 2 3 4 5
我们遇到这种问题首先得把三种任务类型区分开(主任务、微任务、宏任务)。主任务队列执行完之后会去轮询微任务队列,最后再轮询宏任务队列。
setTimeout就是一个宏任务,Promise是微任务。
1 首先顺序执行输出1。
2 同步执行到Promise中,遇到setTimeout(),将它丢进宏任务队列中,所以setTimeout宏任务不执行,resolve也执行不到。
3. 继续向下执行遇到setTimeout,再丢进宏任务队列中。
4. 继续同步执行输出 2
5. 主任务队列执行完,发现没有微任务,所以轮询宏任务,此时有两个宏任务等待执行,按照顺序先进先出,将第一个拿到主任务队列执行。
6. 执行时发现resolve,同步向下执行遇到Promise的第一个then,将它丢进微任务队列,然后再执行又遇到一个then,再丢进微任务队列。
7. 此时主任务队列执行完毕,发现有微任务,先执行微任务,轮询依次输出3和4
8 最后轮询宏任务,输出 5
总结: 任务执行优先级 主任务 > 微任务 > 宏任务 。
本例子宏微任务混合,微任务要再宏任务执行之后才会被触发,则宏任务不执行,微任务队列为空,所以要先执行宏任务。
知识点1: Promise的then也是一个Promise
打印p2的时候,微任务还未执行,所以是pending(等待)状态
如果将console放入setTimeout中,就是在微任务执行完之后,就是fulfilled状态
知识点2: Promise里面 return一个值相当于resolve(),then中的成功回调函数会接收到这个值
知识点3: 在Promise中封装一个Promise,可以使用类、对象或者直接写一个then方法返回等
知识点4:使用Promise封装ajax异步请求
function request() { return new Promise((resolve, reject) => { resolve('成功!') }) } request().then(res => { console.log(res) }) // 结果:成功
知识点5: 自定义请求错误(如下例子,自已封装了一个ajax请求,请求过程中会有各种类型的错误,自定义了两个错误实例 httpError urlError 用于处理用户请求错误)
class httpError extends Error { constructor(msg) { super(msg); this.name = 'httpError' } } class urlError extends Error { constructor(msg) { super(msg); this.name = 'urlError' } } function ajax(url) { return new Promise((resolve, reject) => { if (!/^http/.test(url)) { throw new httpError('请求地址错误') } let xhr = new XMLHttpRequest(); xhr.open('GET', url) xhr.send() xhr.onload = function() { if(this.status === 200) { resolve(JSON.parse(this.response)) } else if (this.status === 404){ reject(new urlError('用户请求路径错误!')) } else { reject('请求错误') } } }) } ajax('url').then(res => { console.log(res) }).catch(error => { if (error instanceof httpError) { alert(error) } else { console.log(error) } })
最后附上一个Promise题目
function executor(resolve, reject) { let rand = Math.random(); console.log(1) console.log(rand) if (rand > 0.5) resolve() else reject() } var p0 = new Promise(executor); var p1 = p0.then((value) => { console.log("succeed-1") return new Promise(executor) }) var p3 = p1.then((value) => { console.log("succeed-2") return new Promise(executor) }) var p4 = p3.then((value) => { console.log("succeed-3") return new Promise(executor) }) p4.catch((error) => { console.log("error") }) console.log(2)
留个悬念,分析看看如何执行?