前端学习开发之【Promise】与【axios】

0.补充

1. 实例对象与函数对象

实例对象:new函数产生的对象;
函数对象:把函数作为对象使用;(操作属性或方法)

2. 回调函数

自己定义的,但自己没有调用,依旧会执行。
同步回调
立即执行,完全执行完了才结束。不会放入队列中。
异步回调
放入队列中将来执行。一开始不直接干,启动之后直接往下执行,然后再执行该回调函数。

3. 错误处理

错误类型

  • ReferenceError:引用变量不存在;
  • TypeError:数据类型不正确;(该类型不存在xxx属性或方法)
  • RangeError:超出范围,死循环;
  • SyntaxError:语法错误。

错误处理

  • 捕获错误:try catch 捕获error.message、stack
  • 抛出错误:throw new Error(’ ')

错误对象
message属性:错误相关信息;
stack属性:函数调用栈记录信息。

1.概述

1. 简介

异步编程

  • 文件操作
  • 数据库操作
  • 定时器

实现异步编程: 回调函数

什么是Promise?
Promise是JS中进行异步编程的解决方案,语法上讲就是一个构造函数,功能上讲promise对象用来封装一个异步操作并可以获取其成功或失败的结果值。

Promise 是一个 ECMAScript 6 提供的类,目的是更加优雅地书写复杂的异步任务。

为什么要用Promise

  1. 指定回调函数,更灵活:启动异步任务—返回promise对象—给promise对象绑定回调函数;以前必须在启动异步任务前就把回调函数准备好;
  2. 支持链式调用,解决回调地狱问题(不断推进,一直嵌套)。

2. Promise状态

  1. pending变resolved
  2. pending 变 rejected
  • Promise只有这两种状态,且一个对象只能改变一次;
  • 无论成功还是失败,都只有一个结果数据;
  • 成功结果为value,失败为reason。

流程
在这里插入图片描述

3. 使用Promise流程

Promise是构造函数,可以实例化对象,接收的参数是函数类型的值,该函数有两个形参,resolve和reject(也是函数类型的数据),成功调用reslove,失败调用reject。

const p=new Promise((resolve,reject)=>{
    
    
//执行器函数 执行异步操作任务
//成功则调用resolve(value),将promise对象的状态设置为成功
//失败调用reject(reason),将promise对象的状态设置为失败
})

then方法:
接收两个参数,都是函数类型的值。成功则执行第一个回调函数,失败则执行第二个回调。

p.then(()=>{
    
    },()=>{
    
    })

4.使用util.pormisify(original)封装

传入一个错误优先的回调函数(即以(err,value)=>{}回调作为最后一个参数),并返回一个promise的版本。
Node.js 内置的 util 模块有一个 promisify() ,该方法将基于回调的函数转换为基于 Promise 的函数。这使您可以将 Promise 链和 async/await 与基于回调的 API 结合使用。

//引入util模块
const util=require('util');
//引入fs模块
const fs=require('fs');
//返回一个新函数
let mineReadFile=util.promisify(fs.readFile);
mineReadFile('./resource/content.txt').then(value=>{
    
    });

5.封装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){
    
    
			if(xhr.status>=200&&xhr.status<300)
			{
    
    
				resolve(xhr.response);
			}else{
    
    
				reject(xhr.status);
			}
		}
	}
}

sendAJAX('http://api')
.then(value=>{
    
    },reason=>{
    
    })

2.理论

1.Promise状态

实例对象中的一个属性 PromiseState

  • pending 未决定的
  • resolved、fullfilled 成功
  • rejected 失败

一个promise对象只能改变一次,且只有一个数据结果,成功数据为value,失败数据为reason。

2. Promise对象的值

实例对象中的另一个属性 PromiseResult
保存着对象成功或失败的结果。
修改该值的函数:

  • resolve;
  • reject。

然后调用then方法对该值进行相关操作。

3. API

注意看清楚是属于函数对象,还是属于实例对象。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
resolve
如果传入参数为非Promise对象,则返回的结果为成功的promise对象;如果传入的参数为promise对象,则参数的结果为resolve的结果。
如果失败,需要用catch捕捉。
在这里插入图片描述
在这里插入图片描述

4.关键问题

如何改变promise状态

  • 调用resolve函数或reject函数;
  • throw ' '抛出错误。

一个promise指定多个回调,都会调用吗

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

改变promise状态与指定回调函数的顺序问题

  • 都有可能,正常情况下先指定回调(then)再改变状态;
  • 如何先改状态再指定回调:在执行器中直接调用resolve或reject;延迟调用then;
  • 什么时候得到数据:先指定回调的话,当状态改变时,回调函数就会调用,得到数据;先改变状态的话,当指定回调时就会调用回调得到数据。

then返回promise对象的结果状态

  • 由then()指定的回调函数执行结果决定;
    在这里插入图片描述
    在这里插入图片描述

异常穿透
前面抛出异常,可以在最后catch,中间可以调用then。
在这里插入图片描述

3.自定义Promise

使用:

let p=new Promise((resolve,reject)=>{
    
    
	resolve('ok');
});
p.then(value=>{
    
    },reason=>{
    
    });

自定义:

  1. 定义整体结构:构造函数含执行器形参(函数类型),在原型链上添加then函数;构造函数中声明reject和resolve函数,并调用执行器,参数为reject和resolve;
  2. 设置reject和resolve函数:先添加属性PromiseState和PromiseResult并设置初始值;再保存实例对象this,然后在两函数中修改变量,(注意函数有形参data为结果值);
  3. throw抛出异常:调用执行器时使用try catch捕获异常,调用reject;
  4. 设置Promise状态只能修改一次:在reject和resolve函数中设置判断,若状态不为pending,则直接返回不进行修改操作;
  5. then方法执行回调:then方法有两个函数类型的形参onResolved和onRejected,当状态为fulfilled时调用前者,(形参为结果值);
  6. 异步任务回调的执行:为了能够在未改变状态时指定回调,需要在then中进行pending判断,增加callback变量,保存onRejected和onResolved两个回调函数;在构造函数的resolve和reject中增加调用回调;
  7. 指定多个回调的实现:callback修改为数组,可以push进多个对象,每个对象包含一个onResolved和一个onRejected;在resolve和reject函数中修改调用每一个回调;
  8. 同步任务修改状态 then方法结果返回:then的返回结果由回调函数的执行结果来决定,修改then函数,返回新建的Promise对象,如果结果是promise,则返回其then调用结果,如果不是promise对象,则调用resolve返回;
  9. 异步任务修改状态then方法结果返回:增加pending判断改为上述;
  10. then方法优化: 封装hen的返回结果由回调函数的执行结果来决定,修改then函数,返回新建的Promise对象,如果结果是promise,则返回其then调用结果,如果不是promise对象,则调用resolve返回
  11. catch方法(异常穿透与值传递):
  12. 封装resolve、reject、all、race函数;
  13. then方法回调函数异步执行:加上定时器;
  14. 封装成class:
function Promise(executor){
    
    
	//添加属性
	this.PromiseState='pending';
	this.PromiseResult=null;
	this.callbacks={
    
    };
	//保存实例对象的this值
	const self=this;
	function resolve(data){
    
    
		if(self.PromiseState !=='pending')return;
		//1.修改对象状态(promiseState)
		self.PromiseState='fulfilled';
		//2.设置对象结果值(promiseResult)
		self.PromiseResult=data;
		setTimeout(()=>{
    
    
			self.callbacks.forEach(item=>{
    
    
				item.onResolved(data);
			})
		})
	}
	function reject(data){
    
    
		if(self.PromiseState !=='pending')return;
		//1.修改对象状态(promiseState)
		self.PromiseState='rejected';
		//2.设置对象结果值(promiseResult)
		self.PromiseResult=data;
		setTimeout(()=>{
    
    
			self.callbacks.forEach(item=>{
    
    
				item.onRejected(data);
			})
		})
		
	}
	try{
    
    
		//同步调用执行器函数
		excutor(resolve,reject);
	}catch(e){
    
    
		reject(e);
	}
	
}
//形参为函数
Promise.prototype.then=function(onResolved,onRejected){
    
    
	const self=this;
	if(typeof onRejected !=='function'){
    
    
		onRejected=reason=>{
    
    
			throw reason;
		}
	}
	if(typeof onResolved!=='function'){
    
    
		onResolved=value=>value;
	}
	return new Promise((resolve,reject)=>{
    
    
		//封装函数
		function callback(type){
    
    
			try{
    
    
				let result=type(this.PromiseResult);
				if(result istanceof Promise){
    
    
					result.then(v=>{
    
    
						resolve(v);
					},r=>{
    
    
						reject(r);
					})
				}else{
    
    
					resolve(result);
				}
			}catch(e){
    
    
				reject(e);
			}
		}
		//调用回调函数
		if(this.PromiseState==='fulfilled'){
    
    
			setTimeout(()=>{
    
    
				callback(onResolved);
			})
		}
		if(this.PromiseState==='rejected'){
    
    
			setTimeout(()=>{
    
    
				callback(onRejected);
			})
			
		}
		if(this.PromiseState==='pending'){
    
    
			//保存回调函数
			this.callbacks.push{
    
    
				onResolved:function(){
    
    
					callback(onResolved);
				},
				onRejected:function(){
    
    
					callback(onRejected);
				}
			}
		}
	})
}
Promise.prototype.catch=function(onRejected){
    
    
	return this.then(ondefined,onRejected);
}

Promise.resolve=function(value){
    
    
	return new Promise((resolve,reject)=>{
    
    
		if(value instanceof Promise){
    
    
			value.then(v=>{
    
    
				resolve(v)
			},r=>{
    
    
				reject(r);
			}
		}else{
    
    
			resolve(value);
		}
	}
}
Promise.reject=function(reason){
    
    
	return new Promise((resolve,reject)=>{
    
    
		reject(reason);
	}
}
Promise.all=function(promises){
    
    
	return new Promise((resolve,reject)=>{
    
    
		let count=0;
		let arr=[];
		for(let i=0;i<promises.length;i++){
    
    
			promises[i].then(v=>{
    
    
				count++;
				arr[i]=v;
				if(count===promises.length){
    
    
					resolve(arr);
				}
			},r=>{
    
    
				reject(r);
			})
		}
	}
}
Promise.race=function(promises){
    
    
	return new Promise((resolve,reject)=>{
    
    
		for(let i=0;i<promises.length;i++){
    
    
			promises[i].then(v=>{
    
    
				resolve(v);
			},r=>{
    
    
				reject(r);
			})
		}
	}
}
class Promise{
    
    
	constructor(executor){
    
    
			//添加属性
	this.PromiseState='pending';
	this.PromiseResult=null;
	this.callbacks={
    
    };
	//保存实例对象的this值
	const self=this;
	function resolve(data){
    
    
		if(self.PromiseState !=='pending')return;
		//1.修改对象状态(promiseState)
		self.PromiseState='fulfilled';
		//2.设置对象结果值(promiseResult)
		self.PromiseResult=data;
		setTimeout(()=>{
    
    
			self.callbacks.forEach(item=>{
    
    
				item.onResolved(data);
			})
		})
	}
	function reject(data){
    
    
		if(self.PromiseState !=='pending')return;
		//1.修改对象状态(promiseState)
		self.PromiseState='rejected';
		//2.设置对象结果值(promiseResult)
		self.PromiseResult=data;
		setTimeout(()=>{
    
    
			self.callbacks.forEach(item=>{
    
    
				item.onRejected(data);
			})
		})
		
	}
	try{
    
    
		//同步调用执行器函数
		excutor(resolve,reject);
	}catch(e){
    
    
		reject(e);
	}
	}
	then((onResolved,onRejected){
    
    
	const self=this;
	if(typeof onRejected !=='function'){
    
    
		onRejected=reason=>{
    
    
			throw reason;
		}
	}
	if(typeof onResolved!=='function'){
    
    
		onResolved=value=>value;
	}
	return new Promise((resolve,reject)=>{
    
    
		//封装函数
		function callback(type){
    
    
			try{
    
    
				let result=type(this.PromiseResult);
				if(result istanceof Promise){
    
    
					result.then(v=>{
    
    
						resolve(v);
					},r=>{
    
    
						reject(r);
					})
				}else{
    
    
					resolve(result);
				}
			}catch(e){
    
    
				reject(e);
			}
		}
		//调用回调函数
		if(this.PromiseState==='fulfilled'){
    
    
			setTimeout(()=>{
    
    
				callback(onResolved);
			})
		}
		if(this.PromiseState==='rejected'){
    
    
			setTimeout(()=>{
    
    
				callback(onRejected);
			})
			
		}
		if(this.PromiseState==='pending'){
    
    
			//保存回调函数
			this.callbacks.push{
    
    
				onResolved:function(){
    
    
					callback(onResolved);
				},
				onRejected:function(){
    
    
					callback(onRejected);
				}
			}
		}
	})
}

	catch(onRejected){
    
    
		return this.then(ondefined,onRejected);
	}

	static resolve(value){
    
    }
	static reject(reason){
    
    }
	static all(promises){
    
    }
	static race(promises){
    
    }
}

4.async与await

1.async函数

  • 返回值为promise对象;
  • promise对象的结果由async函数执行的返回值决定:如果返回值是一个非promise对象,则结果是成功状态的promise对象,结果值为return值;如果返回的结果是一个promise对象,则返回该对象;如果抛出异常,则返回一个失败的promise对象,结果值为抛出值。

2.await表达式

  • await右侧的表达式一般为promise对象,也可以为其他值;

  • 如果表达式是promise对象,则await返回的是promise成功的结果值;

  • 如果右侧是失败的promise对象,必须进行try catch捕获,得到失败的结果;

  • 如果表达式是其他值,直接将此值作为await的返回值。

  • await必须写在async函数中,但async函数中可以没有await;

  • 如果await的promise失败了,就会抛出异常,需要通过try catch捕获处理。

3. async与await结合实践

  1. 错误处理与回调更方便:直接try catch;
  2. 发送ajax时,直接调用封装好的函数。

5.axios

1.简介

axios是基于promise对ajax的封装。Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。

mvvm:
在这里插入图片描述

2.基本使用

默认使用get方式发送无参请求

axios({
    
    
	url:'https://api'
}).then(res=>{
    
    })

指定get方式发送无参请求

axios({
    
    
	url:'https://api'method:'get'
}).then(res=>{
    
    })

指定post方式发送无参请求

axios({
    
    
	url:'https://api'method:'post'
}).then(res=>{
    
    })

get发送有参请求

axios({
    
    
	url:'https://api?key=value',
	method:'get'
}).then(res=>{
    
    })
axios({
    
    
	url:'https://api',
	params:{
    
    
		key:'value',
	},
	method:'get'
}).then(res=>{
    
    })

post发送有参请求

axios({
    
    
	url:'https://api',
	params:{
    
    
		key:'value',
	},
	method:'post'
}).then(res=>{
    
    })

如果使用data而非params发送,则后台接收到的value为null,因为axios使用post携带参数默认使用application/json。
解决:1.使用params 2.服务器端给请求参数加上@requestBody。

3. axios请求方式

get无参

axios.get('url').then(res=>{
    
    }).catch(err=>{
    
    })

get有参

axios.get('url',{
    
    parmas:{
    
    key:'value'}}).then(res=>{
    
    }).catch(err=>{
    
    })

post无参

axios.post('url').then(res=>{
    
    }).catch(err=>{
    
    })

post有参

axios.post('url',"key=value&key2=value2").then(res=>{
    
    }).catch(err=>{
    
    })

使用data传输数据,后台需要将axuios自动转换成java对象,加上@requestBody。
在这里插入图片描述

4.axios并发请求

请求成功响应数组。
可以使用spread函数方法处理响应结果。

axios.all([
	axios.get('url'),
	axios.post('url')])
.then(
	axios.spread((res1,res2)=>{
    
    })
).catch(err=>{
    
    })

5.全局配置

指定默认配置,它将作用于每个请求。

axios.defaults.baseURL='';
axios.defaults.timeout=2000;

6.实例

封装不同实例,实现不同配置

let newVar=axios.create({
    
    
	baseURL:'',
	timeout:5000
});
newVar({
    
    
	url:''
}).then(res=>{
    
    })

7.拦截器

在发起请求或响应对操作进行处理,被 then 或 catch 处理前拦截它们。约等于过滤器

axios两大类拦截器:请求方向的拦截 响应方向拦截。

// 添加请求拦截器
axios.interceptors.request.use(config=>{
    
    
    // 在发送请求之前做些什么
    return config;
  }, error=>{
    
    
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(response=>{
    
    
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  }, error=>{
    
    
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  });

移除拦截器:

const myInterceptor = axios.interceptors.request.use(function () {
    
    /*...*/});
axios.interceptors.request.eject(myInterceptor);

8.axios在vue中的模块封装

  1. 安装npm install --save
  2. 创建request文件夹存放请求函数;
  3. 封装。

传递参数:

import axios from 'axios';
export function request(config,success,fail){
    
    
	axios({
    
    
		url:config
	}).then(res=>{
    
    success();})
	.catch(err=>{
    
    fail();})
}

export function request1(config){
    
    
	axios.defaults,baseURL='';
	axios(config).then(res=>{
    
    config.success(res);})
	.catch(err=>{
    
    config.fail(err);})
	// config={url:'',success:res=>{},fail:err=>{}}
}

promise:

export function request(config){
    
    
	return new Promise((resolve,reject)=>{
    
    
		let newVar=axios.create({
    
    
			baseURL:'',
			timeout:5000
		});
		newVar(config).then(res=>	{
    
    resolve(res);}).catch(err=>{
    
    reject(err);})
	})
}
//调用
request({
    
    url:''}).then(res=>{
    
    }).catch(err=>{
    
    })

创建实例:

export function request(config){
    
    
	let newVar=axios.create({
    
    
		baseURL:'',
		timeout:5000
	});
	return newVar(config);
}

request({
    
    
	url:''}).then(res=>{
    
    })

有能力再进行源码分析

猜你喜欢

转载自blog.csdn.net/qq_46056318/article/details/127338993