Promise是ES6引入针对异步编程的新的解决方案。本质上Promise是一个函数返回的对象,代表了异步任务的最终完成或失败,并且可以给这个Promise对象绑定回调函数,在某个特点的场景调用。
使用Promise的优点是其能够支持回调函数的链式调用,有效缓解回调地狱问题!
PromiseState
PromiseState中保存着Promise对象的状态。
一个Promise对象必然处于以下三种状态之一:pending(初始状态)、fulfilled(成功状态)、rejected(失败状态)。需要注意的是一个Promise对象状态的改变有且只有两种情况,并且只能改变一次:1.由pending变为fulfilled状态,2.由pending变为rejected状态。不存在有pending状态变为成功再变为失败的情况!!!!
PromiseResult
PromiseResult中保存异步任务成功或失败的值,一般用value表示成功的值,reason表示失败的值。可以通过resolve
函数或者reject
函数修改值,在后续回调函数中取出这两个值。
Promise的基本流程
实例一
使用Promise封装fs模块
const fs = require('fs');
// fs读取数据文件
fs.readFile('./context/静夜思.txt',(err,data)=>{
if(err) throw err;
console.log(data.toString());
})
// 使用Promise封装fs模块
const p = new Promise((resolve,reject)=>{
fs.readFile('./context/静夜思.txt',(err,data)=>{
if(err) reject(err);
resolve(data.toString());
})
})
p.then(value => {
console.log(value);
},reason => {
console.warn(reason);
})
使用fs模块读取文件数据时,常常会出现回调地狱的问题!
因此可以使用Promise进行封装,如果出现err则调用reject函数拒绝,并将err作为参数传入;否则则表示成功,调用resolve函数,将成功的值data作为参数传入。之后为实例对象p指定一个回调,也就是调用then方法,该方法接收两个参数,并且这两个参数都是函数形式的,第一个是成功状态的回调,其中的value保存的是上述promise对象成功的值data,第二个是失败状态的回调,可以在此处输出错误警告!
实例二
封装AJAX操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义封装AJAX</title>
</head>
<body>
<button id="btn">点击发送请求</button>
<script>
const btn = document.getElementById('btn');
btn.onclick = function(){
const p = new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest();
xhr.open('GET','https://api.apiopen.top/getJoke');
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(value => {
console.log(value);
},reason => {
console.log(reason);
})
}
</script>
</body>
</html>
总结
用Promise来封装一个异步操作,成功时调用resolve函数,并将成功的结果传递给resolve函数,失败时则调用reject函数,同时将失败的原因传递给reject函数。然后为这个Promise对象指定回调,也就是调用then方法处理成功或失败的结果,该方法接收两个参数,并且两个参数都是函数形式,如果成功则调用第一个函数参数,失败则调用第二个函数!