何为promise
promise是js中异步函数的管理器,promise可以通过链式调用的方式管理一个异步的任务队列,也可以同时处理多个不同的异步任务。比如axios中的并发请求就是通过promise.all方法来进行管理的。
promise解决了那些问题
使用promise之前我们必须要明白promise是用来解决那些问题的,在js的编程里函数分为同步任务和异步任务,而同步任务总是在异步任务完成之后才执行。可实际的开发场景中我们经常会希望等到一个异步任务完成以后再去执行同步任务,比如向后端发送请求等待数据返回之后再去执行页面的渲染。在过去我们会通过回调函数的形式来写
// An highlighted block
$.ajax({
type:'GET',
url:'',
success:callback
})
但是如果callback内部还有异步的任务那么就必须再嵌套一个callback,这样不断的嵌套被称之为回调地狱,这也是我们所不希望看到的。
promise基本使用
Promise 对象是由关键字 new 及其构造函数来创建的,它的参数是一个立即执行的处理器函数(executor function),这个处理函数又接受两个函数作为参数分别是resolve和reject
let myPromise = new Promise(function(resolve, reject){
setTimeout(function(){
resolve("成功!"); // 意味着操作成功完成
}, 250);
// setTimeout(function(){
// reject("失败!"); //意味着操作失败
// }, 250);
});
这里setTimeout(…)来模拟异步代码,实际编码时可能是向后端发起请求
接下来如何获取promise的返回值,就必须知道promise的三种状态
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。
- 已拒绝(rejected): 意味着操作失败。
执行resolve()对应状态更变为fulfilled,reject()对应rejected
一个promise只有状态确定了才会往下执行,这种确定了的状态又称之为settled(已敲定)
// An highlighted block
const P1 = new Promise((r, j) => {
setTimeout(() => {
r('hello word')
}, 3000)
})
p1.then(res=>console.log(res)) // hello word
promise链式调用
promise.then()或者.catch()都是返回一个新的promise,且状态为pending。利用这一特性可以链式的调用promise
const P1 = new Promise((r, j) => {
setTimeout(() => {
r('success')
}, 1000)
}).then((res) => {
console.log('第一个promise', res);
return 'then good'
})
.then((res) => {
console.log('第二个promise' + res)
return 'then good'
})
.then(res => {
console.log('第三个promise' + res)
})
// 第一个promise success
// 第二个promisethen good
// 第三个promisethen good
敲一下重点!!! 不管是.then()还是.catch()默认都是返回状态为fulfilled的promise,生活还得继续不是,想要终止promise链式调用最好的办法就是返回一个状态为pending的promise
const P1 = new Promise((r, j) => {
setTimeout(() => {
r('A')
}, 1000)
}).then((res) => {
console.log('第一个promise', res);
if (res === 'B') {
return '牵手成功'
} else {
return Promise.reject('牵手失败')
}
})
.then((res) => {
console.log('第二个promise' + res)
return 'then good'
})
.catch(err => {
console.log('第二个promise' + err)
})
.then((res) => {
console.log('无论then还是catch,生活还得继续')
});
promise的一些使用场景
获取base64,这个在我上一篇博客有写过
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = (e) => { resolve(e) }
})
图片预加载
const loadImg = (url, width, height) => {
return new Promise((resolve, reject) => {
const img = new Image(width, height)
img.src = url
img.onload = () => {
resolve(img)
}
img.onerror = (e) => {
reject(e)
}
})
}
const url ='https://inews.gtimg.com/newsapp_bt/0/12940052095/1000'
loadImg(url).then((img) => {
document.body.append(imgs)
})
休眠函数
const asleep = (time) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('afterAsleep')
resolve()
}, time)
})
}
asleep(3000).then((res) => {
console.log('beforeAsleep', res)
});
promise多任务管理用法
promise.all 等待所有都完成(或第一个失败),参数是一个数组,返回值也是对应的数组
const all = Array.from({ length: 5 }).map((_, index) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(index * 1000)
}, index * 1000)
})
})
Promise.all(all).then(res => {
console.log('res', res)
}).catch(err => {
console.log('err', err)
})
// [0, 1000, 2000, 3000, 4000]
Promise.race 当一个promise状态确定的时候,Promise.race与其相同的状态,参数是一个数组,返回值是一个promise
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 500);
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// 双方都有决心,但promise2承诺更快
});
// "two"