问题导向
Promise是什么? 如何使用?
如果你都有了答案,可以忽略本文章,或去JS学习地图寻找更多答案
Promise问题
问:一个Promise指定多个成功/失败回调,都会调用吗?
答:都会调用
问:改变Promise状态和指定回调函数谁先谁后?
答:都有可能,正常情况下先指定回调再改变状态,也可以先改变状态再指定回调
问:如何先改变状态,再指定回调?
答:在执行器中调用resolve/reject,将Promise对象赋值给变量,再.then调用
问:什么时候才能得到数据?
答:如果先指定的回调,当状态改变时,回调就出触发,得到数据
如果先改变的状态,当指定回调时,回调才会触发,得到数据
问:Promise.then()返回的新promise的结果状态由什么决定?
答:由then指定的回调函数执行的结果决定,
如果抛出异常,新promise变为rejected,被失败回调捕获
如果任何的是非promise的任意值,新promise变为resolved,value为成功回调中的值
如果返回的是另一个新的promise,此promise的结果就会变为新的promise
注意:
1.then的成功回调,没有返回任何值,新promise的成功回调获取到是undefined
2.then的失败回调,如果没有任何值,等于返回undefined,
新promise是resolved状态,成功回调获取到是undefined
问:Promise如何串联多个操作任务?
答:Promise的then返回一个新的promise,可以根据状态链式调用,
串联多个任务,同步异步都可以,但异步必须包在promise里面
问:Promise的异常传透?(错误统一处理)
答:当使用Promise的then链式调用时,可以在最后指定失败的回调,统一处理
问:中断Promise链?
答:当使用promise的then链式调用时,在中间中断,不在执行后面的回调函数
方法:在回调中返回一个pending状态的promise对象
执行顺序问题
第一题:
setTimeout(() => {
console.log(1)
},0)
new Promise((resolve) => { //excutor马上会执行
console.log(2)
resolve()
}).then(() => {
console.log(3)
}).then(() => {
console.log(4)
})
console.log(5)
执行顺序:2 5 3 4 1
同:2 5
宏:[1]
微:[3]先执行3,才放4进微任务,因为没执行的时候是pending状态
第二题:
const first = () => new Promise((resolve,reject) => {
console.log(3)
let p = new Promise((resolve,reject) => {
console.log(7)
setTimeout(() => {
console.log(5)
resolve(6) //不执行,因为状态不是pending
},0)
resolve(1)
})
resolve(2)
p.then((arg) => {
console.log(arg)
})
})
first().then((arg) =>{
console.log(arg)
})
console.log(4)
执行顺序:3 7 4 1 2 5
同:3 7 4
宏:[5]
微:[1, 2]
第三题:
重点:同层then的同步代码必须执行完,才会把下一个then的回调放到队列中
setTimeout(() => {
console.log(0)
},0)
new Promise(resolve,reject => {
console.log(1)
resolve()
}).then(() => { //#1
console.log(2)
new Promise(resolve,reject => {
console.log(3)
resolve()
}).then(() => { //##1
console.log(4)
}).then(() => {
console.log(5)
})
}).then(() => { //因为这个回调的结果依赖于上一个,不执行完上一个,不会执行
console.log(6)
})
new Promise(resolve,reject => {
console.log(7)
}).then(() => {
console.log(8)
})
执行顺序:1 7 2 3 8 4 6 5 0
同:1 7
异同:3
宏:[0]
微:[2 8 4 6]
头条面试题
async function async1(){
console.log('async1 start') //2
await async2() //回调=微
console.log('async1 end') // 6
}
async function async2(){
console.log('async2') //3
}
console.log('script start') //1
settimeout(function(){ //宏任务
console.log('settimeout') //8
},0)
async1()
new Promise(function(resolve){
console.log('promise1') // 4
resolve()
}).then(function(){//异微
console.log('promise2') //7
})
console.log('script end') //5
其他
Promise.resolve().then(() => { //then返回resolved
console.log(1) //1
}).catch(() => { //不执行
console.log(2)
}).then(() => { //执行
console.log(3) //3
})
Promise.resolve().then(() => { //then返回rejected
console.log(1) //1
throw new Error('error1')
}).catch(() => { //执行2,返回resolved
console.log(2)
}).then(() => { //执行3
console.log(3)
})
Promise.resolve().then(() => { //then返回rejected
console.log(1) //1
throw new Error('error1')
}).catch(() => { //执行2,返回resolved
console.log(2)
}).catch(() => { //catch不执行
console.log(3)
})
应用
加载一张图片
function loadImg(url){
return new Promise((resovle,reject) => {
const img = new Image()
img.src = url
img.onload = () => {
resolve(img)
}
img.onerror = () => {
reject(new Error(`图片加载失败 ${src}` ))
}
})
}
如果失败则显示一张其他的图片
let url = './lunbotu12.jpg'
let errorUrl = './lunbotu2.jpg'
loadPic(url).then(res => {
document.body.appendChild(res)
}).catch((err) => {
let pic = new Image()
pic.src = errorUrl
document.body.appendChild(pic)
}).finally(() => {
console.log('加载完成')
})
批量获取数据
function getUser(names){
let promises = names.map(name => {
return ajax(`xxx${name}`)
})
return Promise.all(promises)
}
getUser(['大神','乔伊']).then(users => {
console.log(users)
})
加载图片,三张加载完再显示到页面中
function loadImg(url){
return new Promise((resovle,reject) => {
const img = new Image()
img.src = url
img.onload = () => {
resolve(img)
}
img.onerror = () => {
reject(new Error(`图片加载失败 ${src}` ))
}
})
}
let p1 = loadImg('地址')
let p2 = loadImg('地址')
let p3 = loadImg('地址')
let result = Promise.all([p1,p2,p3])
result.then(res => {
console.log(res)
result.forEach(item => {
document.body.appendChild(item)
})
},err => {
console.log(err)
})
每隔2秒输出一个user
async function sleep(dalay = 2000){
return new Promise(resovle => {
setTimeout(()=>{
resovle()
}, dalay)
})
}
async function show(){
for(const user of ['大神','乔伊']){
await sleep()
console.log(user)
}
}
show()
学习更多