Promise
入门Promise
介绍1.抽象表达
Promise
是一门新的技术(ES6
规范)
Promise
是JS
中进行异常编程的新解决方案
备注:旧方案是单纯使用回调函数【】
2.具体表达
Promise
是一个构造函数Promise
对象用来封装一个异步操作并可以获取其成功/失败的结果值promise
的状态改变由于Promise
实例中有一个属性:PromiseState
有三种状态
pending 未决定的,初化状态
resolved / fullfilled 成功,如果成功后,则将状态修改成该状态
rejected 失败 如果失败后,则将状态修改成该状态
pending
变为resolved
pending
变为rejected
说明:只有这2种
,且一个promise
对象只能改变一次,无论变为成功还失败,都会有一个结果数据,成功的结果数据一般称为了 value
,失败的结果数据一般称为reason
Promise
对象值实例对象量的另一个属性PromiseResutl
,保存着是异步任务【成功/失败】的结果,这个状态只能使用resolve
或reject
两个对象进行修改
resolve
reject
promise
的执行流程Promise
快速入门案例:
/**
点击按钮, 1s 后显示是否中奖(30%概率中奖)
若中奖弹出 恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
若未中奖弹出 再接再厉
*/
传统方式一:
<body>
<div class="container">
<h2 class="page-header">Promise 初体验</h2>
<button class="btn btn-primary" id="btn">点击抽奖</button>
</div>
<script>
//生成随机数
function rand(m,n){
return Math.ceil(Math.random() * (n-m+1)) + m-1;
}
/**
点击按钮, 1s 后显示是否中奖(30%概率中奖)
若中奖弹出 恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
若未中奖弹出 再接再厉
*/
// 方式一:使用传统方式
//获取元素对象
let bnt = document.getElementById("btn");
// 使用传统方式一;
// 绑定单击事件
bnt.onclick = ()=>{
let result = rand(1,100);
// 使用定时器 1s 后开奖
setTimeout(()=>{
if(result<=30){
alert("恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券");
}else{
alert("再接再厉");
}
},1000);
};
</script>
</body>
Promise
方式二:
// 使用Promise方式二;
// 绑定单击事件
bnt.onclick = ()=>{
// 由于Promise是构造函数,所以可以直接new对象
// 在Promise需要接收一个函数
// 在这个函数中需要两个参数:resolve 和 reject 这个参数都是 `函数类型的数据`
//
let p = new Promise((resolve,reject)=>{
setTimeout(() => {
//30% 1-100 1 2 30
//获取从1 - 100的一个随机数
let n = rand(1, 100);
//判断
if(n <= 30){
resolve(); // 将 promise 对象的状态设置为 『成功』
}else{
reject(); // 将 promise 对象的状态设置为 『失败』
}
}, 1000);
});
// 对回调的结果进行处理
// then需要接收两个回调函数
// 第一个参数:成功后调用
// 第二个参数:失败后调用
p.then(()=>{
alert("恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券");
},
()=>{
alert("再接再厉");
});
<body>
<div class="container">
<h2 class="page-header">Promise 初体验</h2>
<button class="btn btn-primary" id="btn">点击抽奖</button>
</div>
<script>
//生成随机数
function rand(m,n){
return Math.ceil(Math.random() * (n-m+1)) + m-1;
}
/**
点击按钮, 1s 后显示是否中奖(30%概率中奖)
若中奖弹出 恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券
若未中奖弹出 再接再厉
*/
// 方式一:使用传统方式
//获取元素对象
let bnt = document.getElementById("btn");
// 使用Promise方式二;
// 绑定单击事件
bnt.onclick = ()=>{
// 由于Promise是构造函数,所以可以直接new对象
// 在Promise需要接收一个函数
// 在这个函数中需要两个参数:resolve 和 reject 这个参数都是 `函数类型的数据`
//
let p = new Promise((resolve,reject)=>{
setTimeout(() => {
//30% 1-100 1 2 30
//获取从1 - 100的一个随机数
let n = rand(1, 100);
//判断
if(n <= 30){
resolve(n); // 将 promise 对象的状态设置为 『成功』
}else{
reject(n); // 将 promise 对象的状态设置为 『失败』
}
}, 1000);
});
// 对回调的结果进行处理
// then需要接收两个回调函数
// 第一个参数:成功后调用
// 第二个参数:失败后调用
p.then((value)=>{
alert("恭喜恭喜, 奖品为 10万 RMB 劳斯莱斯优惠券,您的中奖数字为"+value);
},
(reason)=>{
alert("再接再厉,您的号码为"+reason);
});
};
</script>
</body>
fs
读取文件使用传统回调函数方式:
// 回调用函数形式
const fs = require('fs');
fs.readFile('./resource/content.txt',(err,data)=>{
// 如果出现异常,抛出
if(err){
throw err;
}
// 没有异常则打印
console.log(data.toString);
});
使用Promise
方式:
// 第一步:创建 Promise对象
const p = new Promise((resolve,reject)=>{
// 第二步:读取文件
fs.readFile('./resource/content.txt',(error,data)=>{
if(data){
resolve(data);
}
if(error){
reject(error);
}
});
});
p.then(
(data)=>{
console.log(data.toString);
},
(err)=>{
throw err;
}
);
Promise
实践练习AJAX
请求传统方式:
<body>
<div class="container">
<h2 class="page-header">Promise 封装 AJAX 操作</h2>
<button class="btn btn-primary" id="btn">点击发送 AJAX</button>
</div>
<script>
//接口地址 https://fanyi.baidu.com/
//获取元素对象
const btn = document.querySelector('#btn');
// btn绑定单击事件
btn.onclick = ()=>{
// 创建对象
let xhr = new XMLHttpRequest();
// 初化url
xhr.open("get","https://fanyi.baidu.com/");
// 发送
xhr.send();
// 对响应结果处理
xhr.onreadystatechange = ()=>{
// 判断是否完成响应
if(xhr.readyState === 4){
if(xhr.status>=200&&xhr.status<300){
alert(xhr.response);
console.log(xhr.response);
}else{
alert(xhr.status);
}
}
};
}
</script>
</body>
Promise
方式
<body>
<div class="container">
<h2 class="page-header">Promise 封装 AJAX 操作</h2>
<button class="btn btn-primary" id="btn">点击发送 AJAX</button>
</div>
<script>
//接口地址 https://fanyi.baidu.com/
//获取元素对象
const btn = document.querySelector('#btn');
btn.onclick = ()=>{
// 创建对象
let p = new Promise((resolve,reject)=>{
let xhr = new XMLHttpRequest();
// 初化url
xhr.open("get","https://api.apiopen.top/getJoke");
// 发送
xhr.send();
// 判断是否成功响应
xhr.onreadystatechange = ()=>{
if(xhr.readyState===4){
if(xhr.status>=200&&xhr.status<300){
resolve(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
// 处理promise的结果
p.then(
(value)=>{
console.log(value);
},
(reason)=>{
console.log(reason);
});
};
</script>
</body>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise 封装 AJAX</title>
<link crossorigin='anonymous' href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h2 class="page-header">Promise 封装 AJAX 操作</h2>
<button class="btn btn-primary" id="btn">点击发送 AJAX</button>
</div>
<script>
//接口地址 https://api.apiopen.top/getJoke
//获取元素对象
const btn = document.querySelector('#btn');
btn.addEventListener('click', function(){
//创建 Promise
const p = new Promise((resolve, reject) => {
//1.创建对象
const xhr = new XMLHttpRequest();
//2. 初始化
xhr.open('GET', 'https://api.apiopen.top/getJoke');
//3. 发送
xhr.send();
//4. 处理响应结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
//判断响应状态码 2xx
if(xhr.status >= 200 && xhr.status < 300){
//控制台输出响应体
resolve(xhr.response);
}else{
//控制台输出响应状态码
reject(xhr.status);
}
}
}
});
//调用then方法
p.then(value=>{
console.log(value);
}, reason=>{
console.warn(reason);
});
});
</script>
</body>
</html>
Promise
封装练习-fs模块案例:
/**
* 封装一个函数 mineReadFile 读取文件内容
* 参数: path 文件路径
* 返回: promise 对象,如果成功resovle,失败返回reject
*/
/**
* 封装一个函数 mineReadFile 读取文件内容
* 参数: path 文件路径
* 返回: promise 对象,如果成功resovle,失败返回reject
*/
// 引入fs对象
const fs = require('fs');
// 封装函数 mineReadFile
function mineReadFile(path){
return new Promise((resovle,reject)=>{
fs.readFile(path,(error,data)=>{
if(error){
reject(error);
}
resovle(data);
})
});
};
// 调用函数测试
mineReadFile("./resource/content.txt")
.then(
(data)=>{
console.log(data);
},
(error)=>{
console.log(error);
});
util.promisify
方法/**
* util.promisify 方法
*/
// 引入模块
const util = require("util");
const fs = require("fs");
// 返回一个新的函数对象
let mineReadFile = util.promisify(fs.readFile);
// 调用函数测试
mineReadFile("./resource/content.txt")
.then(
(data)=>{
console.log(data.toString());
},
(error)=>{
console.log(error);
});
Promise
封装AJAX
请求 /**
* 封装一个函数 sendAJAX 发送 GET AJAX 请求
* 参数 URL
* 返回结果 Promise 对象
*/
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Promise封装AJAX操作title>
head>
<body>
<script>
/**
* 封装一个函数 sendAJAX 发送 GET AJAX 请求
* 参数 URL
* 返回结果 Promise 对象
*/
function sendAJAX(url){
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
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);
}
}
}
});
}
sendAJAX('https://api.apiopen.top/getJok')
.then(value => {
console.log(value);
}, reason => {
console.warn(reason);
});
script>
body>
html>
Promise
的API
Promise
构造函数:Promise(excutor){}
executor
函数:执行器(resolve,reject)=>{}
resolve
函数:内部定义成功时我们调用的函数value=>{}
reject
函数:内部定义失败时我们调用的函数reason=>{}
说明:executor
会在Promise
内部立即同步调用,异常操作在执行器中执行【就是说:传入的箭头函数是立即执行的】
Promise.prototype.then
方法:(onResolved,onRejected)=>{}
onResolved
函数:成功的回调函数 (value)=>{}
onReject
函数:失败的回调函数 (reason)=>{}
说明:指定用于得到成功value
的成功回调和用于得到失败reason
的失败回调返回一个新的promise
对象
Promise.prototype.catch
方法:(onRejected)=>{}
onRejected
函数:失败的回调函数 (reason)=>{}
then()
语法糖,相当于then(undefiend,onRejected);
说明:注意是:catch
方法只能在失败时调用
注意是:then
和catch
方法都在Promise
对象调用的【也就是通过Promise
构造函数创建的对象,对象名调用】,不能直接通过Promise.
的形式调用
<script>
let p = new Promise((resovle,reject)=>{
/**
* 我们可以通过rsovle或reject对象来修改是否成功或失败
*/
// resovle("海康");//设置成功
reject("error");//设置失败
});
// 对p结果处理
// p.then(
// (data)=>{
// console.log(data);
// },
// (error)=>{
// console.log(error);
// }
// )
// 注意是:catch方法只能处理失败后的结果
p.catch((error)=>{
console.log(error);
});
</script>
Promise.resolve
方法:(value)=>{}
value
:成功的数据或promise
对象说明:返回一个成功/失败的promise
对象
注意是:resolve
方法是可以直接通过Promise.resolve("参数")
调用的,并且可以传入参数,如果传入参数是非Promise
对象返回就是成功,如果传入参数是Promise
对象,传入的Promise
对象返回成功就是成功,返回失败就是失败
<script>
// Promise.resolve("参数")方法
/**
* 1.如果传入的参数为 非Promise类型的对象,则返回结果为成功的Promise对象。例如:传入 数值 布尔 等【除了Promse对象】
*
* 2.如果传入的参数为 Promise类型的对象,则返回结果由传入的Promise对象决定,如果传入的Promise返回的结果是成功,则成功,如果传入的Promise返回结果是失败,返回的结果就是失败
*/
let p = Promise.resolve("海康");// 返回结果为:成功
let p2 = Promise.resolve(new Promise((resovle,reject)=>{
/**
* 可以使用 resovle和reject函数对象修改是否成功或失败
*/
// resovle("湛江");
reject("error");
}));
// 对象p2结果进行处理
p2.then(
(data)=>{
console.log(data);
},
(error)=>{
console.log(error);
});
</script>
Promise.reject
方法:(reason)=>{}
reason
:失败的原因说明:返回一个失败的promise
对象,不管传入的参数是什么永远返回的Promise
结果都是失败的
<script>
// 在reject函数中不管传入什么参数,返回的结果永远都失败的
let p = Promise.reject("永远都是失败的reject函数");
p.catch((error)=>{
console.log(error);
});
</script>
Promise.all
方法:(promise)=>{}
promise
:包含n
个promise
的数组说明:返回一个新的promise
,只有所有的promise
都成功才成功,只要有一个失败了就直接失败,注意是:返回所有成功promise
对象组成的数组,失败就是直接返回失败的那个promise
对象
<script>
// 定义几个Promise对象
let p1 = new Promise((resolve,reject)=>{
resolve("湛江");
});
let p2 = Promise.resolve("海康");
let p3 = Promise.resolve("南宁");
/**
* 1.由于三个返回的结果都是成功,所以三者组成的数组返回,总结:成功组成数组全部返回
* 2.如果其中的 p2 返回的结果是失败,则直接返回 p2 的结果
*/
let result = Promise.all([p1,p2,p3]);
</script>
Promise.race
方法:(promise)=>{}
promise
:包含n
个promise
的数组说明:返回一个新的promse
,第一个完成的promise
的结果状态就是最终的结果状态
Promise.reace
方法中的那个promise
对象状态先改变,返回结果就是那个对象的状态,如果那个对象返回成功,则成功,返回失败,则失败
<script>
// 定义几个Promise对象
let p1 = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve("湛江");
},1000);
});
let p2 = Promise.resolve("海康");
let p3 = Promise.resolve("南宁");
/**
* race返回的结果就是由于那个一个最先改状态的那个Promise对象,
* 如果在这个案例中,是第二个先修改状态,所以返回就是第二个,由于返回成功,则成功,如果返回失败,则失败
*/
let result = Promise.race([p1,p2,p3]);
</script>
注意是:resolve()
reject()
all()
race()
这四个方法都可以通过Promise.
的方式来调用的
async
和await
asyn
函数promise
对象promise
对象的结果由async
函数执行的返回值决定
Promise
对象,则返回就会成功的Promise
对象Promise
对象,则Promise
返回成功还是失败,由该Promise
成功还是失败决定Promise
对象asyn
和then
及Promise.resolve()
函数返回值一样的规则
<script>
// async函数
async function main(){
// 1.如果直接返回一个 非Promise对象【如布尔 数值 字符串 null undefiend】,则async函数返回值就是一个成功的promise对象
return "海康"; // 返回是成功的
// 2.如果返回值是:Promise对象,成功还是失败,由该Promise对象决定
return new Promise((resolve,reject)=>{
// 返回失败,则失败
// reject("error");
// 返回成功,则成功
resolve("success");
});
// 3.抛出异常,返回Promise对象是失败的
throw "失败的Promise";
}
let result = main();
alert(result);
</script>
await
表达式await
右侧的表达式一般为promise
对象,但也可以是其它的值promise
对象,并且promise
是成功,await
返回的是promise
成功的值【是获取成功后传入的参数值,如果传入是success
,则返回就是success
】promise
对象,并且promise
是失败,我们需要使用try-catch
来捕获await
语句await
的返回值注意:
await
必须写在async
函数中,但async
函数中可以没有await
await
的promise
失败了,就会抛出异常,需要通过try-catch
捕获处理 <script>
// 注意是:await必须在async
async function main(){
// 1.await右侧是 非Promies对象,await会将该值当返回值返回
let res1 = await "海康";
console.log(res1);
// 2.await右侧是 Promise对象,如果 Promise对象是成功的,则返回成功的值
let p = new Promise((resolve,reject)=>{
resolve("success");
});
let res2 = await p;
console.log(res2);
console.log(typeof res2);
// 3.await右侧是 Promise对象,如果 Promise对象是失败的,则需要`try-catch`来对`await`语句进行捕获
let p2 = new Promise((resolve,reject)=>{
reject("error");
});
try{
let res3 = await p2;
}catch(e){
console.log(e);
}
}
main();
</script>
asyn
函数与await
表达式注意是:util
中的promisify(参数)
是可以将一些API
转换成promise
对象,如:util.promisify(fs.readFile);
使用asyn
函数与await
表达式读取三个文件中的内容,并且拼接在一定输出
const fs = require("fs");
const util = require("util");
const mineReadFile = util.promisify(fs.readFile);
async function main(){
let data1 = await mineReadFile("./resource/1.html")
let data2 = await mineReadFile("./resource/2.html")
let data3 = await mineReadFile("./resource/3.html")
console.log(data1+data2+data3);
}
main();
async
与await
结合发送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>Document</title>
</head>
<body>
<button>获取段子了...</button>
<script>
// 封装 ajax
function sendAJAX(url){
return new Promise((resovle,reject)=>{
// 创建XMLHttpRequest
let xhr = new XMLHttpRequest();
xhr.open('get',url);
xhr.send();
xhr.onreadystatechange = ()=>{
if(xhr.readyState===4){
if(xhr.status>=200&&xhr.status<300){
resovle(xhr.response);
}else{
reject(xhr.status);
}
}
}
});
}
// 使用async与await结合发送ajax请求
// 获取button对象
let bnt = document.getElementsByTagName("button")[0];
// 绑定单击事件
//段子接口地址 https://api.apiopen.top/getJoke
bnt.onclick = async function(){
alert("fdsfs");
let result = await sendAJAX("https://api.apiopen.top/getJoke");
console.log(result);
}
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>async与await结合发送AJAX</title>
</head>
<body>
<button id="btn">点击获取段子</button>
<script>
//axios
function sendAJAX(url){
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
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);
}
}
}
});
}
//段子接口地址 https://api.apiopen.top/getJoke
let btn = document.querySelector('#btn');
btn.addEventListener('click',async function(){
//获取段子信息
let duanzi = await sendAJAX('https://api.apiopen.top/getJoke');
console.log(duanzi);
});
</script>
</body>
</html>