一、回调函数
-
什么是回调函数?
-
就是把函数 A 当作参数传递到 函数 B 中
-
在函数 B 中以行参的方式进行调用
function a(cb) { cb() } function b() { console.log('我是函数 b') } a(b)
-
为什么需要回调函数
- 当我们执行一个异步的行为的时候,我们需要在一个异步行为执行完毕之后做一些事情
- 那么,我们是没有办法提前预知这个异步行为是什么时候完成的
- 我们就只能以回调函数的形式来进行
- 就比如我们刚刚封装过的那个
ajax
函数里面的success
- 我们并不知道 ajax 请求什么时候完成,所以就要以回调函数的形式来进行
二、回调地狱
-
当一个回调函数嵌套一个回调函数的时候
-
就会出现一个嵌套结构
-
当嵌套的多了就会出现回调地狱的情况
-
比如我们发送三个 ajax 请求
- 第一个正常发送
- 第二个请求需要第一个请求的结果中的某一个值作为参数
- 第三个请求需要第二个请求的结果中的某一个值作为参数
ajax({ url: '我是第一个请求', success (res) { // 现在发送第二个请求 ajax({ url: '我是第二个请求', data: { a: res.a, b: res.b }, success (res2) { // 进行第三个请求 ajax({ url: '我是第三个请求', data: { a: res2.a, b: res2.b }, success (res3) { console.log(res3) } }) } }) } })
-
回调地狱,其实就是回调函数嵌套过多导致的
-
当代码成为这个结构以后,已经没有维护的可能了
-
所以我们要把代码写的更加的艺术一些
三、Promise
语法
-
promise
是一个 ES6 的语法 -
承诺的意思,是一个专门用来解决异步 回调地狱 的问题
-
语法:
new Promise(function (resolve, reject) { // resolve 表示成功的回调 // reject 表示失败的回调 }).then(function (res) { // 成功的函数 }).catch(function (err) { // 失败的函数 })
-
promise 就是一个语法
- 我们的每一个异步事件,在执行的时候
- 都会有三个状态,执行中 / 成功 / 失败
- pending 承诺继续
- fulilled 成功
- rejected 失败/拒绝
-
因为它包含了成功的回调函数
-
所以我们就可以使用 promise 来解决多个 ajax 发送的问题
new Promise(function (resolve, reject) { ajax({ url: '第一个请求', success (res) { resolve(res) } }) }).then(function (res) { // 准备发送第二个请求 return new Promise(function (resolve, reject) { ajax({ url: '第二个请求', data: { a: res.a, b: res.b }, success (res) { resolve(res) } }) }) }).then(function (res) { ajax({ url: '第三个请求', data: { a: res.a, b: res.b }, success (res) { console.log(res) } }) })
-
这个时候,我们的代码已经改观了很多了
-
基本已经可以维护了
-
但是对于一个程序员来说,这个样子是不够的
-
我们还需要更加的简化代码
-
所以我们就需要用到一个 es7 的语法了
-
叫做 async/await
四、Promise
对象的常用方法
1.then
-
通过promise对象的then方法可以同时给p1传递成功和失败的回调函数
-
语法: p1.then(成功的回调函数[,失败的回调函数])
-
通过then传递的时候,调用失败的函数,没有报错提示
2.catch
-
通过promise对象的catch方法可以给p1传递失败的回调函数
-
语法: p1.catch(失败的回调函数)
-
通过catch传递的时候,调用失败的函数,有报错提示
3.finally
-
通过promise对象的finally方法可以给p1传递一个函数
-
这个函数会在在promise结束的时候执行,不管是成功还是失败
p1.finally(options=>{ console.log('不管成功还是失败,只要结束了,我就会执行') console.log(options) })
4.all
-
语法:Promise.all([promise对象1,promise对象2,…]).then(values=>{})
-
then里面的函数会在数组的所有promise对象结束的时候调用
-
values就是所有的promise对象调用成功回调的时候传入的实参的集合
-
如果某一个promise对象执行了reject,all就会抛出遇到的第一个错误
Promise.all([p1,p2,p3]) .then((values)=>{ console.log(Date.now()-current);// 5000 console.log(values) })
5.race
-
语法:Promise.race([promise对象1,promise对象2,…]).then(value=>{})
-
then里面的函数会在数组的最快的那一个promise对象结束的时候调用
-
如果最快的那个resolve,就获取resolve中的实参
-
如果最快的那个reject,就抛出错误
Promise.race([p1,p2,p3]).then((value)=>{ console.log(Date.now()-current);// 3000 console.log(value) })
五、async
/await
es7解决方案
-
async/await
是一个 es7 的语法 -
这个语法是 回调地狱的终极解决方案
-
语法:
async function fn() { const res = await promise对象 }
-
这个是一个特殊的函数方式
-
可以 await 一个 promise 对象
-
可以把异步代码写的看起来像同步代码
-
只要是一个 promise 对象,那么我们就可以使用
async/await
来书写async function fn() { const res = new Promise(function (resolve, reject) { ajax({ url: '第一个地址', success (res) { resolve(res) } }) }) // res 就可以得到请求的结果 const res2 = new Promise(function (resolve, reject) { ajax({ url: '第二个地址', data: { a: res.a, b: res.b }, success (res) { resolve(res) } }) }) const res3 = new Promise(function (resolve, reject) { ajax({ url: '第三个地址', data: { a: res2.a, b: res2.b }, success (res) { resolve(res) } }) }) // res3 就是我们要的结果 console.log(res3) }
- 这样的异步代码写的就看起来像一个同步代码了
六、try
/catch
语法
let p1 = new Promise(function(resolve,reject){
setTimeout(function(){
let num = 10;
if(num>5){
resolve('成功'+num)
}else{
reject('这是失败信息')
}
})
})
// promise语法
// p1.then((data)=>{
// console.log(data)
// },(err)=>{
// console.log(err)
// })
// 使用try...catch语法配合await语法
// await接收的是promise对象通过resolve传入的实参
let data;
try{
data = await p1;
}catch(err){
console.log(err)
}
console.log(data)
console.log(123)
七、Promise
封装ajax
Promise
的形式封装ajax
function pGetSend(url) {
// 利用 promise 帮我们做一个 异步的 ajax 请求
var p1 = new Promise(function (resolve, reject) {
// 直接发送一个 ajax 请求
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.onload = function () {
resolve(xhr.responseText) // 在请求成功的时候调用一下 resolve()
}
xhr.send()
})
return p1
}
ajax
相关案例