Promise
Promise 介绍与基本使用
Promise 是什么?
- 抽象表达
1)Promise 是一门新的技术(ES6规范)
2)Promise 是JS中进行异步编程的新解决方法
备注:旧方案是单纯使用回调函数
异步编程
* fs 文件操作(nodejs的一个模块)
require('fs').readFile('./index.html',(err,data) => {})
* 数据库操作
* AJAX
$.get('./list',(data) => {})
* 定时器
setTimeout( () => {},2000)
- 具体表达
1)从语法上来说:Promise 是一个构造函数,所以可以 new 出一个Promise的实例
2)从功能上来说:Promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值。
3)Promise是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。
-
主要用于异步计算
-
可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
-
可以在对象之间传递和操作promise,帮助我们处理队列
-
promise对象用来封装一个异步操作并可以获取其结果
为什么要用Promise
指定回调函数的方式更加灵活
- 旧的:必须在启动异步任务前指定。
- promise:启动异步任务 =》返回promise对象 =》给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)
支持链式调用,可以解决回调地狱问题
什么是回调地狱?
回调函数嵌套调用, 外部回调函数异步执行的结果是嵌套的回调执行的条件。回调地狱就是在回调函数中再嵌套回调函数的一种现象。如代码所示:
setTimeout(()=>{
console.log(1);
setTimeout(()=>{
console.log(2);
setTimeout(()=>{
console.log(3);
},1000)
},1000)
},1000)
回调地狱的缺点
- 不便于阅读
- 不便于异常处理
解决方案
promise +async/await
Promise 的基本使用
promise的案例
需求:
1、点击按钮,2s之后显示是否中奖(30%概率中奖)
2、若中奖,弹出 中奖了
3、若未中奖,弹出再接再厉
<button id="btn">抽奖</button>
<script>
function rand(m, n) {
return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
}
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
// 定时器
// setTimeout(()=>{
// let n = rand(1,100)
// if(n <= 30){
// alert("中奖了")
// }else{
// alert('再接再厉')
// }
// },2000)
// Promise 形式实现
//resolve 解决 函数类型的数据
// reject 拒绝 函数类型的数据
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1, 100)
if (n <= 30) {
resolve(n); // 将 Promise 对象的状态设置为成功
} else {
reject(n) // 将 Promise 对象的状态设置为失败
}
}, 2000)
});
p.then(
n => { alert("中奖了,数字为"+n) },
n => { alert("再接再厉,数字为"+n) }
)
})
</script>
fs读取文件
const fs = require('fs')
// 回调函数的形式
// fs.readFile('../static/demo.txt',(err,data) => {
// if(err) throw err
// console.log(data.toString())
// })
// Promise
const p = new Promise((resolve,reject) => {
fs.readFile('../static/demo.txt',(err,data) => {
if(err) reject(err)
resolve(data)
})
})
p.then(
res =>{ console.log(res.toString()) },
err => { console.log(err) }
)
/**
* 封装一个函数 readFile 读取文件内容
* 参数:path 文件路径
* 返回:promise对象
*/
function readFile(path){
return new Promise((resolve,reject) => {
require('fs').readFile(path,(err,data) =>{
if(err) reject(err)
resolve(data)
})
})
}
readFile('../static/demo.txt').then(
res => {console.log(res.toString())},
err => {console.log(err)}
)
// util.promisify
// 引入util模块
const util = require('util');
// 引入fs模块
const fs = require('fs');
// 返回一个新的函数
let readFile = util.promisify(fs.readFile)
readFile('../static/demo.txt').then(res => {
console.log(res.toString());
})
文件读取结果如下:
promise Ajax的使用
<button id="btn">发送AJAX请求</button>
<script>
function ajaxFun(url){
return new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest();
xhr.open('GET',url);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState == '4'){
if(xhr.status >= 200 && xhr.status < 300 ){
resolve(xhr.response)
}else{
reject(xhr.status)
}
}
}
})
}
document.getElementById('btn').addEventListener('click',function(){
// const p = new Promise((resolve,reject) => {
// const xhr = new XMLHttpRequest();
// xhr.open('GET','http://127.0.0.1:8000/server');
// xhr.send();
// xhr.onreadystatechange = function(){
// if(xhr.readyState == '4'){
// if(xhr.status >= 200 && xhr.status < 300 ){
// resolve(xhr.response)
// }else{
// reject(xhr.status)
// }
// }
// }
// })
// p.then(
// res => { console.log(res) },
// err => { console.error(err); }
// )
ajaxFun('http://127.0.0.1:8000/server').then(
res => { console.log(res) },
err => { console.error(err); }
)
})
</script>
Promise 的状态
- 实例对象中的一个属性 【PromiseState】
- pending[待定]初始状态
- resolved/fulfilled[实现]操作成功
- rejected[被否决]操作失败
- Promise的状态改变
- pending 变为resolved
- pending 变为rejected
说明:
只有这2种,且一个promise对象只能改变一次。promise状态一经改变,不会再变。
当promise状态发生改变,就会触发then()里的响应函数处理后续步骤;
无论成功还是失败,都会有1个结果数据
- promise 实例对象的另一个属性 【PromiseResult】
保存着对象【成功/失败】的结果。
resolve reject函数可以修改该值。
Promise 的基本流程
Promise API
Promise构造函数:Promise(executor){}
- executor函数:执行器
(resolve,rejecte) => {}
- resolve函数:内部定义成功时我们调用的函数 res => {}
- reject函数:内部定义失败时我们调用的函数 err => {}
- 说明:executor 会在Promise 内部立即同步调用,异步操作在执行器中执行。
/**
* (resolve,reject) => {} 被称为执行器函数 同步调用
*/
const p = new Promise((resolve,reject) => {
console.log(111); // 同步调用
})
console.log(222);
执行结果如下:
Promise.prototype.then方法:(onResolved,onRejected) => {}
- onResolved函数:成功的回调函数 res => {}
- onRejected函数:失败的回调函数 err => {}
- 说明:指定用于得到成功 res 的 的成功回调和用户得到失败 err 的失败回调,
返回一个新的promise对象
Promise.prototype.catch方法:(onRejected) => {}
- onRejected 函数:失败的回调函数 err => {}
- 在Promise状态为rejected时执行,then方法捕捉到Promise的状态为rejected,就执行catch方法里面的操作.
const p1 = new Promise((resolve,reject) => {
reject('error')
})
p1.catch(err =>{ console.log(err); })
Promise.resolve方法:(res) => {}
- res:成功的数据或promise对象
- 说明:返回一个成功/失败的promise对象
// 如果传入的参数为 非Promise类型的对象,则返回的结果为成功的promise对象
// 如果传入的参数为promise对象,则参数的结果决定了 resolve 的结果。
let p = Promise.resolve(520);
let p1 = Promise.resolve(new Promise((resolve,reject) => {
resolve('OK')
}))
let p2 = Promise.resolve(new Promise((resolve,reject) => {
reject('Error')
}))
p2.catch(err => {
console.log(err)
})
console.log("p",p);
console.log("p1",p1);
console.log("p2",p2);
Promise.reject方法:(err) => {}
- err:失败的原因
- 说明:返回一个失败的Promise对象
- reject方法返回的是错误信息,将Promise的状态置为rejected
// 不管你传入什么 都是失败,失败的值是你传入的值
let p = Promise.reject(520);
p.catch(err => {
console.log("p - err",err)
})
let p1 = Promise.reject(new Promise((resolve,reject) => {
resolve('OK')
}))
p1.catch(err => {
console.log("p1 - err",err)
})
console.log("p",p);
console.log("p1",p1);
Promise.all方法:(promises) => {}
- promises:包含n个promise的数组
- 说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败。
let p = new Promise((resolve,reject) => {
resolve("p 成功")
})
let p1 = new Promise((resolve,reject) => {
resolve("p1 成功")
})
let p2 = new Promise((resolve,reject) => {
resolve("p2 成功")
})
let result = Promise.all([p,p1,p2]);
console.log(result);
let p = new Promise((resolve,reject) => {
resolve("p 成功")
})
let p1 = new Promise((resolve,reject) => {
reject("p1 失败")
})
p1.catch((err)=>{
console.log(err);
})
let p2 = new Promise((resolve,reject) => {
resolve("p2 成功")
})
let result = Promise.all([p,p1,p2]);
console.log(result);
Promise.race方法:(promises) => {}
- promises:包含n个promise的数组
- 说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态。
let p = new Promise((resolve,reject) => {
setTimeout( ()=>{
resolve("p 成功")
},1000)
})
let p1 = new Promise((resolve,reject) => {
resolve("p1 成功")
})
let p2 = new Promise((resolve,reject) => {
resolve("p2 成功")
})
let result = Promise.race([p,p1,p2]);
console.log(result);
第一个完成的promise是p1