Promise 是ES6引入的异步编程的新解决方案。
语法上Promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
Promise 构造函数: Promise(excutor){}
Promise.prototype.then 方法
Promise.prototype.catch 方法
Promise
实例化 Promise 对象;
Promise 回调函数的两个形参(默认规范): resolve 和 reject ,也是两个函数;调用这两形参函数分别代表构造出的新对象的两种状态:成功 和 失败;
const p = new Promise(function(resolve,reject){
setTimeout(function(){
let data = "成功获取用户数据";
resolve(data); // 调用 resolve 函数,在then 中对应 value,data 作为参数传给了 value
},1000);
});
// 调用 promise 里的 then 方法,这个方法有两个回调函数作为参数,分别对应 resovle 和 reject 两种状态
// 成功的形参叫 value ,失败的形参叫 reason,也是默认规范
p.then(function(value){ // Promise 中调用了 resolve ,then 中对应的调用 value
console.log(value); // 成功获取用户数据 会显示 resolve 返回的数据;
},function(reason){
});
Promise实例化的 p 对象有三种状态:初始化,成功 和 失败;
当调用 resolve 函数时,即标识 p 对象的状态为成功时,将在 then 方法里调用第一个参数函数,即 value 对应的函数;
当调用 reject 函数时,即标识 p 对象的状态为失败时,那 then 方法将执行第二个回调函数,即 reason 对应的函数;
上面实例中,p 对象调用了 resolve 并返回了 data ,那么 then 方法中会执行第一个函数,并把 data 作为参数,传给了 value ,最后输出;
如果异步函数 setTimout 中调用了 reject 函数呢?
const p = new Promise(function (resolve, reject) {
setTimeout(function () {
let err = "数据读取失败";
reject(err); // 调用了 reject 函数,相当于设定 p 对象的状态为失败,then 方法会执行第二个函数
}, 1000);
});
p.then(function (value) {
console.log(value);
}, function (reason) { // 因调用了 reject 函数,所以 then 方法执行第二个函数
console.log(reason); // 数据读取失败
});
通过这种方式 ,把异步任务封装在 Promise 的对象 p 里面; 通过 resolve 和 reject 函数来改变 p 对象的状态,从而影响 then 方法里的回调函数;即“成功”就调第一个函数,“失败”就调第二个函数;
Promise封装读取文件
需要 Node 环境,先引入 fs 模块,再调用方法读取文件;
const fs = require('fs');
fs.readFile('./res/为学.md',(err,data)=>{
if(err) throw err;
console.log(data.toString());
});
通过 Promise 来封装:
const fs = require('fs');
const p = new Promise(function (resolve, reject) {
// 读取文件是异步操作
fs.readFile('./res/为学.md', (err, data) => {
// 如果失败,改变为失败状态 reject,可设置失败值为 err
if (err) reject(err);
// 如果成功,改变状态为成功
resolve(data);
});
});
// 不是一定要用 value 和 reason 作为形参
p.then(function (value) {
console.log(value.toString());
}, function (reason) {
console.log("读取失败");
});
明明几行代码就能做好的事情,还用费这么大劲么?
因为单个任务看不出来,要是有多个异步任务,尤其是有先后顺序的异步任务时,使这种方法会不断缩进,产生回调地狱问题,使用 Promise 就不会出这个问题。
Promise封装AJAX
创建原生的AJAX
// 原生创建AJAX
//1, 创建对象
const xhr = new XMLHttpRequest();
// 2, 初始化
xhr.open("get", "https://api.apiopen.top/api/sentences");
// 3, 发送
xhr.send();
// 4, 事件绑定,处理响应结果
xhr.onreadystatechange = function () {
// 判断
if (xhr.readyState === 4) {
// 判断响应状态码
if (xhr.status >= 200 && xhr.status < 300) {
// 表示成功
console.log(xhr.response);
} else {
// 表示失败
console.log(xhr.status);
}
}
}
用 Promise 封装 AJAX
const p = new Promise(function(resolve,reject){
const xhr = new XMLHttpRequest();
xhr.open('get','https://api.apiopen.top/api/sentences');
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >=200 && xhr.status <300){
resolve(xhr.response);
}else{
reject("xhr.status :" + xhr.status);
}
}
}
});
// 指定回调
p.then(function(value){
console.log(value);
},function(reason){
console.log(reason);
});
Promise 的 then 方法
then