异步操作
- fs文件(fs是node下的一个模块,可以对磁盘进行修改)
require('fs').readFile('./index.html',(err,data)=>{})
- 数据库操作
- Ajax
$.get('/server',(data)=>{})
- 定时器
setTimeout(()=>{},2000);
基础特点
- 支持链式调用,可以解决回调地狱问题
- 指定回调函数的方式更加灵活
promise 初步体验
要求:
- 设置按钮进行抽奖
- 设置一秒延时
- 设置30%概率中奖
- 出现结果给出弹窗(含有原生与promise形式实现,主要区别在于JS)
<!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>
<style>
button{
width: 200px;
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<button>点击抽奖</button>
<script>
//生成随机数
function rand(m,n){
//返回向上取整的数值,并控制再m,n之间
return Math.ceil(Math.random() * (n-m+1)) + m + 1 ;
}
//获取元素对象
const btn = document.querySelector('button')
//设置定时器
btn.addEventListener('click',function(){
//Promise对象实例化
//resolve与reject是自定义的两个变量,一般写为这两种
//成功时用resolve,失败时用reject
const p = new Promise((resolve,reject)=>{
setTimeout(() => {
//设置百分之三十的概率中奖
let n = rand(1,100);
if(n<=30){
resolve(); //调用时讲promise的对象设置为成功
}else{
reject(); //调用时讲promise的对象设置为失败
}
},1000)
});
//调用then方法,指定回调函数
p.then((resolve)=>{
alert('恭喜中奖')
},(reject)=>{
alert('再接再厉')
})
})
</script>
</body>
</html>
要求增加:若是成功返回中奖数字
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)
})
})
promise封装fs使用
//创建FS实例对象
const fs = require('fs');
//创建promise对象
let p = new Promise((resolve,reject)=>{
fs.readFile('./fist.txt',(err,data)=>{
//如果出错
if(err){
reject(err);
}else{
resolve(data);
}
})
p.then((value)=>{
console.log(value.toString());
},(reason)=>{
console.log(reason);
})
})
promise对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 GET 请求</title>
<style>
#result{
width: 200px;
height: 100px;
border: solid 1px black;
}
</style>
</head>
<body>
<button>点击发送请求</button>
<div id="result"></div>
<script>
//获取button元素
const btn = document.getElementsByTagName('button')[0];
//在div中显示
const result = document.getElementById('result');
//绑定button事件
btn.onclick = function(){
//创建promise对象
const p = new Promise((resolve,reject)=>{
//1.创建对象
const xhr = new XMLHttpRequest();
//2.设置初始化,设置请求方法和URL
xhr.open('POST','https://api.apiopen.top/getJoke');
//3.发送
xhr.send();
//4.时间绑定,处理服务端返回的结果
//onreadystatechange即获取状态改变
//readystate是xhr里面的一个属性,表示状态原本有0,1,2,3,4
//0表示未初始化,1表示open()方法已经调用完毕,2表示send()方法调用完毕
//3表示服务端返回了部分结果,4表示客户端返回了所有结果
xhr.onreadystatechange = function(){
//我们应该在4的时候承接返回结果
if(xhr.readyState === 4){
console.log("客户端已经返回了所有结果")
//判断响应状态码 200 404 403 401 500
//2开头的都是成功
if(xhr.status >= 200 && xhr.status < 300){
//处理结果,行,头,空行,体
//1.响应行
//设置result的文本
resolve(xhr.response);
}else {
//输出状态码
reject(xhr.status)
}
}
}
});
//调用then()方法
p.then(value=>{
result.innerHTML = value;
},reason=>{
result.innerHTML = reason;
})
}
</script>
</body>
</html>
until.promisefy方法进行promise风格转换
const util = require('util');
const fs = require('fs');
const stat = util.promisify(fs.stat);
stat('.').then((stats) => {
// 运行操作
}).catch((error) => {
// 处理错误
});
- 最后一个参数是函数
- 回调函数的参数为 (err, result),前面是可能的错误,后面是正常的结果
promise状态改变
- 状态指实例对象中的一个属性:PromiseState
- 一共三个属性:pending(未决定的),rejected/fullfilled(成功),resolved(失败)
- pending变为resolved(成功时)
- pending变为rejected(失败时)
说明:改变情况只有这两种,只能改变一次,无论成功与否,都会有一个 数据结果,成功的一般时value,失败一般叫reason(主要在回调中实现)
promise对象的值
- 实例对象中的另一个属性:PromiseResult
- 保存异步任务对象成功或者失败时候的结果
promise基本流程
promise中的API
- Promise构造函数:Promise(excutor){}
- executor函数:执行器(resolve,reject)=>{}
- resolve函数:内部定义成功时我们调用的函数 value=>{}
- reject函数:内部定义失败时调用的函数 reason=>{}
说明:executor会在promise内部立即同步调用,异步操作在执行器中运行。
- Promise.prototype.then方法:(onResolved,onRejected)=>{}
- onResolved函数:成功的回调函数(value)=>{}
- onRejected函数:失败的回调函数(reason)=>{}
说明:指定用于得到成功的Value的成功回调和用于得到失败的reason的失败回调返回一个新的promise对象
- catch方法:(onRejected)=>{},只会捕捉失败时的回调
- onRejected函数:失败的回调函数(reason)=>{}
- Promise.resolve方法:(value)=>{}
<!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>
<script>
//如果传入的参数为 非Promise 类型的对象,则返回的结果为成功Promise对象
let p1 = Promise.resolve(521);
//如果传入的参数为 Promise 对象,则参数结果决定了resolve的结果
let p2 = Promise.resolve(new Promise((resolve,reject)=>{
resolve('success');
})
)
</script>
</body>
</html>
说明:返回一个成功/失败的promise对象
- Promise.reject方法:(value)=>{}
说明:返回一个失败的promise对象
- Promise.all方法:(promises)=>{}
<!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>
<script>
let p1 = new Promise((resolve,reject)=>{
resolve('OK');
})
let p2 = Promise.resolve("Happy new year")
let p3 = Promise.reject("fail")
const result = Promise.all([p1,p2]);
console.log(result);//此时为成功
const result = Promise.all([p1,p2,p3]);//此时为失败
</script>
</body>
</html>
说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败就失败
- Promise.race方法:(promises)=>{}
说明:返回一个新的promise对象,第一个完成的promise的结果状态就是最终的结果状态。
promise几个关键问题
- 修改状态
<script>
let p = new Promise((resolve,reject)=>{
//1.resolve函数,pending->fulfilled/resolved
resolve('OK');
//2.reject函数,pending->rejected
reject('Fail');
//3.抛出错误,pending->rejected
throw '出问题了';
})
</script>
- 一个promise指定多个成功/失败回调函数,都会调用吗?
当promise状态改变后,回调函数都会调用。
- 改变promise状态和指定的会叫函数谁先谁后
- 都有可能,正常情况下时先指定回调再改变状态,但也可以先改变状态再指定回调
- 如何先改变状态再指定回调:①在执行器executor中直接调用resolve/reject②延迟更长事件才调用
let p = new Promise((resolve,reject)=>{
resolve('OK');
});
let p = new Promise((resolve,reject)=>{
//设置一秒的延迟
setTimeout(()=>{
resolve('OK');
},1000)
});
//设置两秒的延迟
setTimeout(()=>{
p.then(value=>{
},reason=>{
})
},2000)
- 什么时候能得到数据:①如果先指定的回调,那当状态发生改变时,回调函数就会调用获取数据②如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
- promise.then()返回的新promise的结果状态由上面决定
- 简单表达:由then()指定的回调函数的执行结果决定
- 详细描述:①如果抛出异常,新promise变为rejected,reason为抛出的异常②如果返回的时非promise的任何值,新promise变为resolved,value为返回的值③如果返回的是另一个新promise,此promise的结果会成为新promise的结果
- promise异常穿透
- 当使用promise的then链式调用,可以再最后指定失败的回调
- 前面任何操作出现异常,都会传到最后失败的回调中处理
- 终端promise链
retuen new Promise(()=>{});
async函数
- 结果是promise对象
await表达式
- await必须卸载async中,但async中可以没有await
- 如果await中的promise失败了,就会抛出异常,需要通过try...catch捕获处理
async与await的结合使用
<script>
const fs = require('fs');
const util = require('util');
const mineReadFile = util.promisfy(fs.readFile);
async function main(){
try{
let data1 = await mineReadFile('./api.html');
let data2 = await mineReadFile('./fist.html');
let data3 = await mineReadFile('./second.html');
}
}catch(e){
console.log(e);
}
</script>
async与await结合发送ajax请求
<script>
function sendAjax(url){
return new Promise((resolve,reject)=>{
})
let btn = document.querySelector(#btn);
btn.addEventListener('click',async function(){
let content = await sendAjax('http.baidu.com');
})
}
</script>