一、介绍
- 是什么
- Promise 是 JS 中进行异步编程的新解决方案;
- 从语法上来说:Promise 是一个构造函数;
- 从功能上来说:Promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值。
- 优点
- 指定回调函数的方式更加灵活:旧的异步任务必须在其启动前指定,而 Promise 是启动异步任务 => 返回 promise 对象 => 给 promise 对象绑定回调函数(可以指定多个)
- 支持链式调用,解决回调地狱(回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件)的问题。
1.1 初体验
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</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 初体验</h2>
<button class="btn btn-primary" id="btn">点击抽奖</button>
</div>
</body>
<script type="text/javascript">
function rand(m, n) {
return Math.ceil(Math.random() * (n-m+1)) + m-1
}
const btn = document.querySelector('#btn');
btn.addEventListener('click', function(){
const n = rand(1,100)
//定时器方式
// setTimeout(() => n<=30 ? alert('恭喜中奖') : alert('再接再厉'), 1000)
//Promise 形式实现
// resolve 成功回调函数
// reject 失败回调函数
const p = new Promise((resolve, reject)=>
setTimeout(()=> n<=30 ? resolve(n) : reject(n), 1000))
//p.then(resolve(), reject())
// value 结果值
// reason 失败原因
p.then(value=>alert('恭喜中奖,号码:'+value), reason=>alert('再接再厉,号码:'+reason))
})
</script>
</html>
- Promise 调用流程
pending
:悬而未决的resolved
:成功的rejected
:失败的
1.2 Promise函数
- Promise 基本函数
executor会在 Promise内部立即同步调用 ,异步操作在执行器中执行。
- executor函数 : 执行器
(resolve, reject) => {}
- resolve函数 : 内部定义成功时我们调用的函数
value => {}
- reject函数 : 内部定义失败时我们调用的函数
reason => {}
- then函数:Promise.prototype.
then(onResolved, onRejected) => {}
- catch函数:Promise.prototype.
catch(onRejected) => {}
new Promise((resolve,reject)=>{
// if(success-condition) resolve(value/result)
// if(failed-condition) reject(reason)
}).then(value=>{
// do something with(value)
}).catch(reason=>{
// react with cause(reason)
})
- Promise.
resolve(value) => {}
返回一个成功 /失败的 promise对象
- value: 成功的数据或 promise对象;
- 如果传入的参数为非Promise类型的对象,则返回的结果是成功的Promise对象;
- 如果传入的参数为Promise类型的对象,则参数的结果结果决定了返回的Promise对象结果。
- Promise.
reject(reason) => {}
返回一个失败的 promise对象
- reason: 失败的原因
- 如果传入的参数为非Promise类型的对象,则返回的结果是失败的Promise对象;
- 如果传入的参数为Promise类型的对象,仍返回的结果是失败的Promise对象,返回的Promise结果是传入的Promise对象。
const p1 = Promise.resolve("Success")
const p2 = Promise.resolve(new Promise((resolve,reject)=>{
// if(success-condition) resolve(value/result) -- p2 is fufilled
// if(failed-condition) reject(reason) -- p2 is rejected
}))
const p3 = Promise.reject("Failed")
const p4 = Promise.resolve(new Promise((resolve,reject)=>{
// if(success-condition) resolve(value/result) -- p4 is rejected
// if(failed-condition) reject(reason) -- p4 is rejected
}))
- Promise.
all((promises) => {})
返回一个新的 promise, 只有所有的 promise都成功才成功 , 只要有一个失败了就直接失败。
- promises: 包含 n个 promise的数组
- Promise.
race(promises) => {}
返回一个新的 promise, 第一个完成的 promise的结果状态就是最终的结果状态。
- promises: 包含 n个 promise的数组
const p1 = Promise.resolve("Success")
const p2 = Promise.resolve("Done")
const p3 = new Promise((resolve,reject)=>{
// if(success-condition) resolve(value/result) -- allResult is resolved
// if(failed-condition) reject(reason) -- allResult is rejected
})
const allResult = Promise.all([p1,p2,p3])
const raceResult = Promise.race([p1,p2,p3])
1.3 封装 Ajax 请求
<!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>
</body>
<script>
//封装Ajax请求
function sendAjax(url) {
return new Promise((resolve, reject)=>{
//1.创建对象
const xhr = new XMLHttpRequest()
//2.初始化
xhr.open('GET', url)
//3.发送
xhr.send()
//4.处理响应结果
xhr.onreadystatechange = function(){
if(xhr.readyState === 4)
xhr.status >= 200 && xhr.status < 300 ? resolve(xhr.response) : reject(xhr.status)
}
})
}
//点击按钮调用Ajax
const btn = document.querySelector('#btn')
const url = 'https://api.apiopen.top/getJoke'
btn.addEventListener('click', ()=>sendAjax(url).
then(value=>console.log(value)).
catch(reason=>console.error(reason)))
</script>
</html>
1.4 async 和 await
- async 函数
- 函数的返回值为promise 对象
- promise 对象的结果由async 函数执行的返回值决定
- await 表达式
await 必须写在async 函数中, 但async 函数中可以没有await
- await 右侧的表达式一般为promise 对象, 但也可以是其它的值
- 如果表达式是promise 对象, await 返回的是promise 成功的值
- 如果await 的promise 失败了, 就会抛出异常, 需要通过try…catch 捕获处理
- 如果表达式是其它值, 直接将此值作为await 的返回值
<!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>
</body>
<script>
//封装Ajax请求
function sendAjax(url) {
return new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.send()
xhr.onreadystatechange = function(){
if(xhr.readyState === 4)
xhr.status >= 200 && xhr.status < 300 ? resolve(xhr.response) : reject(xhr.status)
}
})
}
//1. 需要拼接多个异步请求的处理结果时
const btn = document.querySelector('#btn')
const url1 = 'https://api.apiopen.top/getJoke'
const url2 = 'https://api.apiopen.top/getJoke'
const url3 = 'https://api.apiopen.top/getJoke'
//2. async + await 组合使用,解决回调地狱问题,且比链式调用更优美。
btn.addEventListener('click', async function(){
try {
let result1 = await sendAjax(url1)
let result2 = await sendAjax(url2)
let result3 = await sendAjax(url3)
console.log(result1 + result2 + result3)
}catch(e){
console.error(e)
}
})
</script>
</html>