简介
1. 什么是Promise?
- Promise是JS中进行异步编程的新解决方案(fs 文件操作,数据库操作,AJAX,定时器)
- Promise是一个构造函数,promise对象用来封装一个异步操作并可以获取其成功/失败的结果值
2. Promise的优点
- 指定回调函数的方式更加灵活
- 支持链式调用,可以解决回调地狱问题
回调地狱
- 含义:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
- 缺点:不便于阅读;不便于异常处理
使用
简单使用
<h1>Promise初体验</h1>
<hr />
<button id="btn">点我抽奖</button>
<script>
//生成随机数
function rand(m, n) {
return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
}
document.getElementById("btn").onclick = function () {
const p = new Promise((resolve, reject) => {
setTimeout(() => {
let n = rand(1, 100);
if (n <= 30) {
resolve(n); // 将Promise对象的状态设置为 成功
} else {
reject(n); // 将Promise对象的状态设置为 失败
}
}, 1000);
});
// 调用then方法
p.then(
// 成功回调
(value) => {
alert("中奖了!您的中奖数字为:" + value);
},
// 失败回调
(reason) => {
alert("啥也没有,您的号码为:" + reason);
}
);
};
</script>
fs文件读取
const fs = require("fs");
function mineReadFile(path) {
return new Promise((resolve, reject) => {
fs.readFile(path, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
mineReadFile("./note.txt").then(
(value) => {
console.log(value.toString());
},
(reason) => {
console.log(reason);
}
);
const fs = require("fs");
const util = require("util");
let mineReadFile = util.promisify(fs.readFile);
mineReadFile("./note.txt").then(
(value) => {
console.log(value.toString());
},
(reason) => {
console.log(reason);
}
);
AJAX请求
<h1>Promise 封装 AJAX</h1>
<hr />
<button id="btn">点我发送 AJAX请求</button>
<script>
document.getElementById("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>
Promise的状态改变
- Promise的状态指的是Promise实例对象中的一个属性
- 改变只有两种:pending 变为 resolved / fullfilled 或者是 pending 变为 rejected
- pending 是初始默认值,表示未决定的
- 一个promise对象只能改变一次,无论变为成功还是失败,都会有一个结果数据
Promise对象的值
- Promise实例对象中的另一个属性,保存的是异步任务成功或失败的结果
- resolve 和 reject 函数才可以修改这个值
Promise的基本流程

Promise 的 API
Promise()
const p = new Promise((resolve, reject) => {})
/*
executor 函数:(resolve, reject) => {} 也叫执行器函数
resolve 函数:内部定义成功时调用的函数 value => {}
reject 函数:内部定义失败时调用的函数 reason => {}
说明:executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行
*/
Promise.prototype.then(onResolved, onRejected) => {}
p.then(onResolved, onRejected) => {}
/*
onResolved 函数:成功的回调函数 value => {}
onRejected 函数:失败的回调函数 reason => {}
说明:指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调,返回一个新的 promise 对象
*/
Promise.prototype.catch(onRejected) => {}
const p = new Promise((resolve, reject) => {
reject("error!dudu!");
});
p.catch((reason) => {
console.log(reason); // error!dudu!
});
Promise.resolve()
// 如果传入的参数为 非promise类型的对象,返回的结果为成功promise对象
Promise.resolve(1208).then((value) => {
console.log(value); // 1208
});
// 如果传入的参数为 promise类型的对象,则参数的结果决定了 resolve 的结果,如果参数成功结果就是成功
Promise.resolve(p).then(
(value) => {
console.log("成功了~", value);
},
(reason) => {
console.log("失败了~", reason);
}
);
Promise.reject()
// 不管参数是什么,返回都是一个失败的promise对象,对象的值就是参数的值
Promise.reject(1208).catch((reason) => {
console.log(reason); // 1208
});
Promise.reject(
new Promise((resolve, reject) => {
resolve("success!dudu!");
})
).catch((reason) => {
console.log(reason); // Promise { 'success!dudu!' } 成功的promise对象
});
Promise.all()
const p = new Promise((resolve, reject) => {
reject("error!dudu!");
});
const p0 = new Promise((resolve, reject) => {
reject("defeat!dudu!");
});
const p2 = new Promise((resolve, reject) => {
resolve("success!dudu!");
});
const p3 = new Promise((resolve, reject) => {
resolve("victory!dudu!");
});
// 返回的promise对象只有当数组中的所有对象都成功时才成功
Promise.all([p, p0, p2]).then(
(value) => {
console.log("成功了~", value);
},
(reason) => {
console.log("失败了~", reason); // 失败了~ error!dudu! 失败的返回值是数组中第一个失败对象的值
}
);
Promise.all([p3, p2]).then(
(value) => {
console.log("成功了~", value); // 成功了~ [ 'victory!dudu!', 'success!dudu!' ] 成功的值所有对象组成的数组
},
(reason) => {
console.log("失败了~", reason);
}
);
Promise.race()
const p = new Promise((resolve, reject) => {
reject("error!dudu!");
});
const p2 = new Promise((resolve, reject) => {
resolve("success!dudu!");
});
// 返回的promise对象与数组中先得到结果的promise对象相同
Promise.race([p, p2]).then(
(value) => {
console.log("成功了~", value);
},
(reason) => {
console.log("失败了~", reason);
}
);
一些关键问题
1. 修改Promise对象状态的方法
调用 resolve方法将状态从 pending 修改为 resolved
const p = new Promise((resolve, reject) => {
resolve("dudu");
});
console.log(p);
调用 reject方法将状态从 pending 修改为 rejected
const p = new Promise((resolve, reject) => {
reject("dudu");
});
console.log(p);
通过抛出错误的方式,将状态从 pending 修改为 rejected
const p = new Promise((resolve, reject) => {
throw "dudu";
});
console.log(p);
2. 多个回调的执行
当Promise对象的状态改变时,对应的多个回调都会执行
const p = new Promise((resolve, reject) => {
resolve("dudu");
});
// 下面指定的两个回调都会执行
p.then((value) => {
console.log("1.成功了...", value);
});
p.then((value) => {
console.log("2.成功了...", value);
});
3. 改变promise状态和指定回调函数的先后顺序
先改变状态再指定回调:使用同步代码改变状态 或 回调也在异步中指定
const p = new Promise((resolve, reject) => {
resolve("dudu");
});
p.then(
(value) => {
console.log("成功了...", value);
},
(reason) => {
console.log("失败了...", reason);
}
);
先指定回调再改变状态:使用异步代码改变状态
const p = new Promise((resolve, reject) => {
setTimeout(() => {
reject("zhou");
}, 1000);
});
p.then(
(value) => {
console.log("成功了...", value);
},
(reason) => {
console.log("失败了...", reason);
}
);
4. promise.then() 返回的新 promise 的结果状态
const p = new Promise((resolve, reject) => {
resolve("zhou");
});
/*
result 是一个promise对象,它的值由回调方法的结果决定
1. 如果抛出异常,result的状态为失败,值为回调throw的内容
2. 如果返回结果为非promise类型的对象,result的状态为成功,值为回调返回的值
3. 如果返回结果为promise类型的对象,result由回调中返回的对象来决定
*/
const result = p.then((value) => {
console.log("成功了...", value);
// throw "zh ou";
// return 123;
return new Promise((resolve, reject) => {
// resolve("我在回调里成功了");
reject("我在回调里失败了");
});
});
console.log(result);
5. promise串联多个操作任务
由于promise的then方法返回的还是promise对象,可以进行链式调用
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("dudu");
}, 1000);
});
p.then((value) => {
console.log("成功了...", value);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("dududu");
}, 1000);
});
}).then((value) => {
console.log("成功了...", value);
});
6. promise异常穿透
当使用 promise 的 then 链式调用时,可以在最后指定失败的回调,前面的任何操作出了异常,都会传到最后失败的回调中处理
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("dudu");
// reject("dudududududu");
}, 1000);
});
p.then((value) => {
console.log("成功了...", value);
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve("dududu");
reject("dudududududu");
}, 1000);
});
})
.then((value) => {
console.log("成功了...", value);
})
.then((value) => {
console.log("成功了...", value);
})
.catch((reason) => {
console.log(reason);
});
7. 中断Promise链
含义:当使用promise的then链式调用时,在中间间断,不再调用后面的回调函数
方式:在回调函数中返回一个pending状态的promise对象
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("dudu");
}, 1000);
});
p.then((value) => {
console.log("成功了...", value);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("dududu");
}, 1000);
});
})
.then((value) => {
console.log("成功了...", value);
// 返回一个pending状态的promise对象
return new Promise(() => {});
})
.then((value) => {
console.log("成功了...", value);
})
.catch((reason) => {
console.log(reason);
});
async 和 await
1. async 函数
- 函数的返回值为promise对象
- promise 对象的结果由 async 函数执行的返回值决定
// 和then方法返回值的规则相同
async function fn() {
// return 123;
// return new Promise((resolve, reject) => {
// reject("OK");
// });
throw "error";
}
console.log(fn());
2. await 表达式
- await 右侧的表达式一般为 promise 对象,但也可以使其他的值
- 如果是 promise 对象,await 返回的是 promise 成功的值
- 如果是其他值,直接将此值作为 await 的返回值
async function fn() {
// let r1 = await new Promise((resolve, reject) => {
// resolve("OK");
// });
// let r2 = await 200;
// console.log(r2);
try {
let r3 = await new Promise((resolve, reject) => {
reject("error");
});
} catch (error) {
console.log(error);
}
}
fn();
注意:
- await 必须写在 async 函数中,但 async 函数中可以没有 await
- 如果 await 的 promise 失败了,就会抛出异常,需要通过 try…catch 捕获处理
3. 两个实例
读取三个文件
const fs = require("fs");
const util = require("util");
let mineReadFile = util.promisify(fs.readFile);
async function main() {
try {
let data1 = await mineReadFile("./note.txt");
let data2 = await mineReadFile("./note.txt");
let data3 = await mineReadFile("./note.txt");
console.log(data1, data2, data3);
} catch (error) {
console.log(error);
}
}
main();
发送AJAX请求
async function main() {
try {
let data = await axios({
method: "GET",
url: "https://api.apiopen.top/getJoke",
});
console.log(data);
} catch (error) {
console.log(error);
}
}
main();
可以省略回调函数,书写比较简洁清晰
1688

被折叠的 条评论
为什么被折叠?



