Promise和Axios

Promise与axios

一:Promise

定义:Promise是JS中进行异步编程的新解决方案,代替了单纯使用回调函数。

1.1异步操作都有哪些?

  1. fs文件操作
    • require('fs').readFile('./index.html',(err,data)=>{})
  2. 数据库操作
  3. AJAX
    • $.get('/server',(data)=>{})
  4. 定时器
    • setTimeout(()=>{},2000)

具体表达:

  1. 从语法上讲:Promise是一个构造函数
  2. 从功能上讲:Promise对象用来封装一个异步操作并可以获取其成功\失败的结果值

1.2为什么要用Promise?

  1. 指定回调函数的方式更加灵活

Promise和Axios_第1张图片

  1. 支持链式调用,可以解决回调地狱问题
    1. 什么是回调地狱:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
    2. 回调地狱:不便于阅读、不便于异常处理
    3. Promise和Axios_第2张图片

2.1定时器Promise案例:

// Promise 形式实现
// resolve 解决  函数类型的数据
// reject 拒绝  函数类型的数据
const p = new Promise((resolve,reject) => {
    setTimeout(() => {
        //获取1-100的一个随机数
        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)
})

2.2fs读取文件

//Promise 形式
let p = new Promise((resolve , reject) => {
    fs.readFile('./resource/content.txt',(err, data) => {
        //如果出错
        if(err) reject(err)
        //如果成功
        resolve(data)
    })
})

//调用 then
p.then(value => {
    console.log(value.toString())
}, reason => {
    console.log(reason)
})

2.3AJAX请求

const p = new Promise((resolve,reject) => {
    //1.创建对象
    const xhr = new XMLHttpRequest()
    //2. 初始化
    xhr.open('GET','https://api.apiopen.top/getJok')
    //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)
            }
        }
    }
})

p.then(value=>{
    console.log(value)
},reason=>{
    console.log(reason)
})

2.4util.promisify方法封装fs读取文件操作:

//引入 util 模块
const util = require('util')
//引入 fs模块
const fs = require('fs')
//返回一个新的promise函数(可以避免自己手动封装)
let mineReadFile = util.promisify(fs.readFile)
mineReadFile('./resource/content.txt'.then(value => {
    console.log(value.toString())
}))

2.5封装AJAX请求

function sendAJAX(url){
    return new Promise((resolve,reject) => {
    //1.创建对象
    const xhr = new XMLHttpRequest()
    xhr.responseType = 'json'
    //2. 初始化
    xhr.open('GET',url)
    //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)
            }
        }
    }
})
}
sendAJAX('https://api.apiopen.top/getJok').then(value=>{
    console.log(value)
},reason=>{
    console.warn(reason)
})

3.1promise的状态改变

Promise实例对象中的一个属性 【PromiseState】

  • pending 未决定的(初始的)
  • resolved / fullfilled 成功
  • rejected 失败

Promise状态的改变

  1. pending变为resolved
  2. pending变为rejected

说明:只有这两种状态改变,并且一个promise对象只能改变一次

无论变为成功还是失败,都会有一个结果数据

成功的结果数据我们一般称为value,失败的结果数据一般称为reason

3.2Promise 对象的值

实例对象中的另一个属性 【PromiseResult】

保存着异步任务【成功/失败】的结果

  • resolve
  • reject

Promise和Axios_第3张图片

3.3Promise基本工作流程

Promise和Axios_第4张图片

Promise和Axios_第5张图片

解释:new Promise后在Promise内部封装自己的异步任务,之后执行异步任务,如果成功了执行resolve(),状态变为resoloved,之后通过then调用成功的回调函数,失败同样

3.4Promise的API

Promise和Axios_第6张图片

  1. Promise.resolve方法:属于promise函数对象,不属于实例对象

(value) => {}

​ value:成功的数据或者promise对象

​ 说明:返回一个成功/失败的promise对象

//如果传入的参数为非Promise类型的对象,则返回的结果为成功的promise对象
//如果传入的参数为Promise对象,则参数的结果决定了resolve的结果
let p1 = Promise.resolve(555)
//此时p1状态为resolved,值为555
let p2 = Promise.resolve(new Promise((resolve, reject) =>{
    reject('Error!')
}))
//此时P2的状态为rejected,值为Error
p2.catch(reason => {
    console.log(reason)
})
  1. Promise.reject方法同样属于函数对象,不属于实例对象

Promise和Axios_第7张图片

无论返回什么值都是失败值,状态都为失败

p3中状态值为失败,失败的结果为传入的那个成功的Promise对象

Promise和Axios_第8张图片

案例:Promise和Axios_第9张图片

Promise和Axios_第10张图片

7.promise.race()

Promise和Axios_第11张图片

Promise和Axios_第12张图片

Promise和Axios_第13张图片

Promise和Axios_第14张图片

4.1Promise的几个关键问题

4.1.1.如何改变Promise的状态

Promise和Axios_第15张图片

Promise和Axios_第16张图片

4.1.2.一个promise指定多个成功/失败回调函数,都会调用吗

当promise改变为对应的状态时都会调用

Promise和Axios_第17张图片

4.1.3.改变Promise状态和指定回调函数谁先谁后?

Promise和Axios_第18张图片

Promise和Axios_第19张图片

4.1.4.promise.then()返回的新promise的结果状态由什么决定

Promise和Axios_第20张图片

Promise和Axios_第21张图片

4.1.5.promise如何串联多个操作任务

  1. promise的then()返回一个新的promise,可以开成then()的链式调用

  2. 通过then的链式调用串联多个同步/异步任务

Promise和Axios_第22张图片

4.1.6.处理穿透

  1. 当使用promise的then链式调用时,可以在最后指定失败的回调
  2. 前面任何操作除了异常,都会传到最后失败的回调中处理,前面的.then都没有作用

Promise和Axios_第23张图片

4.1.7.如何中断Promise链条?

Promise和Axios_第24张图片

只有一种方式,就是返回一个pedding状态的Promise对象

手写Promise

暂未实现…

5.1async函数

  1. 函数的返回值为promise对象
  2. promise对象的结果由async函数执行的返回值决定
async function main(){
    //1.如果返回的值是一个非Promise类型的数据  
    //return 521  //状态为成功  值为返回的这个值
    //2.如果返回的是一个Promise对象
    return new Promise((resolve,reject) => {
        //resolve('ok')   成功
        //reject('Error')   失败
        //3.抛出异常
        throw "oh NO"  //失败  值为抛出的这个值
    })
}

5.2.await表达式

  1. await右侧的表达式一般为promise对象,但也可以是其他的值
  2. 如果表达式是promise对象,await返回的是promise成功的值
  3. 如果表达式是其他值,直接将此值作为await的返回值
  4. 注意事项:
    • await必须写在async函数中,但async函数中可以没有await
    • 如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
async function main(){
    let p = new Promise((resolve,reject) => {
        //resolve('ok')   下面的res返回的是ok
        reject('Error')
    })
    //1.右侧是promise的情况
    let res = await p  //成功时为成功的值
    //2. 右侧为其他类型的数据
    let res2 = await 20  //返回20
    //3.如果promise是失败的状态
    try{
        let res3 = await p    
    }catch(e){
        console.log(e)  //返回Error
    }
}

main()

async和await

//将resource目录下的1.html  2.html  3.html文件内容连接在一起
const fs = require('fs')
const util = require('util')
const mineReadFile =util.promisify(fs.readFile)
// fs.readFile('./resource/1.html',(err,data1) => {
//     if (err) throw err
//     fs.readFile('./resource/2.html',(err,data2) => {
//         if (err) throw err
//         fs.readFile('./resource/3.html',(err,data3) => {
//             if (err) throw err
//             console.log(data1 + data2 + data3)
//         })
//     })
// })

//async和await
async function main() {
    try{
        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)
    }catch (e) {
        console.log(e.code)
    }
}

async和await结合发送Ajax请求

<button id = 'btn'>点击获取段子button>
function sendAJAX(url){
    return new Promise((resolve,reject) => {
    //1.创建对象
    const xhr = new XMLHttpRequest()
    xhr.responseType = 'json'
    //2. 初始化
    xhr.open('GET',url)
    //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)
            }
        }
    }
})
}

let btn = document.querySelector('#btn')

btn.addEventListener('click',async function(){
    let duanzi = await sendAJAX('http://api.apipoen.top/getJoke')
    console.log(duanzi)
})

二:Axios

概念:Axios是专注于网络数据请求的一个库

相比于原生的XMLHttpRequest对象,axios简单易用

相比于jQuery,axios更加轻量化,只专注于网络数据请求

1.1使用axios发起GET请求

axios发起get请求的语法:

axios.get('url',{params:{/*参数*/}}).then(callback)

//实例代码
var url = 'http://www.liulongbin.top:3006/api/get'
// 	请求的参数对象,请求参数  ?name= zs&age=20
var paramsObj = {name:'zs', age:20}
// 调用axios.get() 发起GET请求
axios.get(url, { params:paramsObj }).then(function(res){
    //res.data 是服务器返回的数据
    var result = res.data
    console.log(res)
})

1.2使用axios发起POST请求

axios发起post请求的语法:

axios.post('url',{/*参数*/}).then(callback)

具体的请求示例如下:

//请求的url地址
var url = 'http://www.liulongbin.top:3006/api/post'
// 要提交到服务器的数据
var dataObj = { location : '北京' , address : '顺义'}
// 调用 axios.post() 发起POST请求
axios.post(url, dataObj).then(function(res){
    //res.data 是服务器返回的数据
    var result = res.data
    console.log(result)
})

1.3直接使用axios发起请求

axios也提供了类似于jQuery中$.ajax()的函数,语法如下:

axios({
    method:'请求类型'url:'请求的URL地址'data:{/* POST数据  */}params:{/* GET参数 */}
}).then(callback)

直接使用axios发起GET请求

axios({
    method:'GET',
    url : 'http://www.liulongbin.top:3006/api/get',
    params:{
        //GET参数要通过params属性提供
        name:'zs',
        age:20
    }
}).then(function(res){
    console.log(res.data)
})

直接使用axios发起POST请求

axios({
    method:'POST',
    url:'http://www.liulongbin.top:3006/api/post',
    data:{
        // POST 数据要通过data属性提供
        bookname:'111',
        price:666
    }
}).then(function(res){
    console.log(res.data)
})

2.1axios基本使用

 		//1.获取按钮
        const btns = document.querySelectorAll('button')
        //第一个
        btn[0].onclick = function () {
            // 发送AJAX请求
            axios({
                method:'get',
                //url
                url:'http://127.0.0.1:3000/posts/2'
            }).then(response => {
                console.log(response)
            })
        }
        //2.添加一篇新的文章
        btn[1].onclick = function () {
            // 发送AJAX请求
            axios({
                method:'post',
                //url
                url:'http://127.0.0.1:3000/posts',
                //设置请求体
                data:{
                    title:'今天天气不错',
                    author:'张三'
                }
            }).then(response => {
                console.log(response)
            })
        }
        //3.更新数据
        btn[2].onclick = function () {
            // 发送AJAX请求
            axios({
                method:'put',
                //url
                url:'http://127.0.0.1:3000/posts/3',
                //设置请求体
                data:{
                    title:'今天天气不错',
                    author:'左超然'
                }
            }).then(response => {
                console.log(response)
            })
        }
        //4.删除数据
        btn[3].onclick = function () {
            // 发送AJAX请求
            axios({
                method:'delete',
                //url
                url:'http://127.0.0.1:3000/posts/3',

            }).then(response => {
                console.log(response)
            })
        }

2.2axios其他方式发送请求

用axios.request({})方法

const btns = document.querySelectorAll('button')
//发送GET请求
btns[0].onclick = function(){
    //axios()
    axios.request({
        method:'GET',
        url:'http://127.0.0.1:3000/comments'
    }).then(response => {
        console.log(response)
    })
}

用axios.post()发送post请求,添加一条comments

const btns = document.querySelectorAll('button')
//发送GET请求
btns[0].onclick = function(){
    axios.post(
		url:'http://127.0.0.1:3000/comments',
        {
        	"body":'喜大普奔',
        	"postId": 2 
        }
 ).then((response) => {
     console.log(response)
 })
}

3.1axios请求响应结果的结构

Promise和Axios_第25张图片

config:请求的配置对象

data:请求体中的内容(数据)

headers:请求头的内容

request:原生的AJAX请求内容

status:请求状态码

statusText:请求内容

4.1.axios配置对象详细说明

4.2.axios的默认配置

const bens = document.querySelectorAll('button')
//默认配置
axios.defaults.method = 'GET'  //设置默认的请求类型为GET
axios.defaults.baseURL = 'http://localhost:3000'  //设置基础URL
axios.defaults.params = {id:100}  //默认参数为id=100    http://127.0.0.1?id=100
axios.defaults.timeout =  3000  //超时时间为3s
btns[0].onclick = function(){
    axios({
        url:'/posts'
    }).then(response => {
        console.log(response)
    })
}

4.3.axios创建实例对象发送请求

const btns = document.querySelectorAll('button')
//创建实例对象
const duanzi = axios.create({
    baseURl:'https://api.apiopen.top',
    timeout: 2000
})
//此时duanzi是axios的一个实例对象,它和axios对象的功能几乎是一样的
//请求方式1
duanzi({
    url:'/getJoke'
}).then(response => {
    console.log(response.data)
})
//请求方式2
duanzi.get('/getJoke').then(response => {
    console.log(response.data)
})
//上述请求方式1和请求方式2效果一样

实例对象有什么作用?

如果我们的项目的接口不是来自于一个服务器,那么使用默认配置就不行了 因为默认配置前面的域名只能设置为一个,可以创建两个axios实例对象,分别用实例对象发起ajax请求

5.1.axios拦截器

axios拦截器分为请求拦截器和响应拦截器

//Promise
// 设置请求拦截器
axios.interceptors.request.use(function(config){
    console.log("请求拦截器 成功")
    config.params = {a:100}
    return config
    //throw 'error'  //抛出错误 之后后续的拦截器就只能走失败的拦截器了
},function(error){
    console.log('请求拦截器 失败')
    return Promise.reject(error)
})

//设置相应拦截器
axios.interceptors.response.use(function(response){
    console.log('响应拦截器 成功')
    return response.data
},function(error){
    console.log('响应拦截器 失败')
    return Promise.reject(error)
})

//发送请求
axios({
    method:'GET',
    url:'http://127.0.0.1:3000/posts'
}).then(response => {
    console.log('自定义回调处理成功的结果')
}).catch(reason => {
    console.log('自定义失败回调')
})

config参数:配置对象

可以修改config中的参数

response:响应体内容

如果一直都是成功的

Promise和Axios_第26张图片

如果请求拦截器中抛出了错误

Promise和Axios_第27张图片

如果有多个请求拦截器和响应拦截器 则请求拦截器后面的先执行 响应拦截器前面的先执行

Promise和Axios_第28张图片

6.1.axios取消请求

//获取按钮
const btns = document.querySelectorAll('button')
//2.声明全局变量
let cancel = null
//发送请求
btn[0].onclick = function(){
    axios({
        method:'GET',
        url:'http://localhost:3000/posts',
        //1.添加配置对象的属性
        cancelToken: new axios.CancelToken(function(c){
            //3.将c的值赋值给cancel
            cancel = c
            
        }).then(response =>{
            console.log(response)
        })
    })
}
btn[1].onclick = function(){
    cancel()
}

检测上一次的请求是否已经完成

Promise和Axios_第29张图片

//获取按钮
const btns = document.querySelectorAll('button')
//2.声明全局变量
let cancel = null
//发送请求
btn[0].onclick = function(){
    //检测上一次的请求是否已经完成
    if(cancel !== null){
        //如果没有完成 取消上一次的请求  
        cancel()
    }
    axios({
        method:'GET',
        url:'http://localhost:3000/posts',
        //1.添加配置对象的属性
        cancelToken: new axios.CancelToken(function(c){
            //3.将c的值赋值给cancel
            cancel = c
            
        }).then(response =>{
			console.log(response)
            //将cancel的值初始化设置
            cancel = null
        })
    })
}
cancel = c
        
    }).then(response =>{
        console.log(response)
    })
})

}
btn[1].onclick = function(){
cancel()
}


检测上一次的请求是否已经完成

[外链图片转存中...(img-ijmF3poX-1663677739499)]

```js
//获取按钮
const btns = document.querySelectorAll('button')
//2.声明全局变量
let cancel = null
//发送请求
btn[0].onclick = function(){
    //检测上一次的请求是否已经完成
    if(cancel !== null){
        //如果没有完成 取消上一次的请求  
        cancel()
    }
    axios({
        method:'GET',
        url:'http://localhost:3000/posts',
        //1.添加配置对象的属性
        cancelToken: new axios.CancelToken(function(c){
            //3.将c的值赋值给cancel
            cancel = c
            
        }).then(response =>{
			console.log(response)
            //将cancel的值初始化设置
            cancel = null
        })
    })
}

你可能感兴趣的:(JavaScript知识点,javascript,前端,开发语言)