Bootstrap

前端工程化18-邂逅Promise(待更新)

6、邂逅Promise

6.1、函数对象与实例对象

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>准备_函数对象与实例对象</title>
</head>
<body>
  <script>
    /* 
    	函数对象、实例对象
					1.函数对象: 将函数作为对象使用时, 简称为函数对象。
					2.实例对象: new 构造函数或类产生的对象, 我们称之为实例对象。
    */
		//函数对象
		function Person (name,age){
			this.name = name
			this.age = age
		}
		Person.a = 1 //将Person看成一个对象
		
	    //一个小的面试点
		Person.name="英叔"	
        console.log(Person.name); //输出结果为Person 而不是林正英
		
		
		const p1 = new Person('老刘',18) //p1是Person的实例对象
		console.log(p1);
		
  </script>
</body>
</html>

6.2、回调函数的分类

要区分那些函数进浏览器回调队列那些不进

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>准备_回调函数的分类</title>
</head>
<body>
  <script>
    /* 
			前序知识:什么是回调?---我们定义的,我们没有调用,最终执行了。

				1.同步的回调函数: 
						理解: 立即在主线程上执行, 不会放入回调队列中。
						例子: 数组遍历相关的回调函数 
				2.异步的回调函数: 
						理解: 不会立即执行, 会放入回调队列中以后执行
						例子: 定时器回调 / ajax回调 
    */

		//演示同步的回调函数
		/* let arr = [1,3,5,7,9]
		arr.forEach((item)=>{
			console.log(item);
		})
		console.log('主线程的代码'); */

		//演示异步的回调函数
		/* setTimeout(()=>{
			console.log('@');
		},2000)
		console.log('主线程'); */
		
  </script>
</body>
</html>

6.3、JavaScript中的error

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>准备_js中的error</title>
</head>
<body>

<script>
  /* 
  	进一步理解JS中的错误(Error)和错误处理
    mdn文档: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Error

			1. 错误的类型
						Error: 所有错误的父类型
						ReferenceError: 引用的变量不存在
						TypeError: 数据类型不正确
						RangeError: 数据值不在其所允许的范围内--死循环
						SyntaxError: 语法错误
			2. 错误处理
						捕获错误: try{}catch(){}
						抛出错误: throw error
			3. 错误对象
						message属性: 错误相关信息
						stack属性: 记录信息
  */

	//演示:ReferenceError: 引用的变量不存在
	/* console.log(a); */

	//演示:TypeError: 数据类型不正确
	/* const demo = ()=>{}
	demo()() */

	//演示:RangeError: 数据值不在其所允许的范围内
	/* const demo = ()=>{demo()}
	demo() */

	//演示:SyntaxError: 语法错误
	/* console.log(1; */

	//如何捕获一个错误
	//try中放可能出现错误的代码,一旦出现错误立即停止try中代码的执行,调用catch,并携带错误信息
	/* try {
		console.log(1);
		console.log(a);
		console.log(2);
	} catch (error) {
		console.log('代码执行出错了,错误的原因是:',error);
	} */

	//如何抛出一个错误
	function demo(){
		const date = Date.now()
		if(date % 2 === 0){
			console.log('偶数,可以正常工作');
		}else{
			throw new Error('奇数,不可以工作!')
		}
	}
	try {
		demo()
	} catch (error) {
		debugger;
		console.log('@',error);
	}
</script>
</body>
</html>

6.4、初识Promise

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>初识Promise</title>
</head>
<body>
  <!-- 
		Promise是什么?
				1.抽象表达:
						(1).Promise是一门新的技术(ES6提出的)
						(2).Promise是JS中异步编程的新方案(旧方案是谁?---纯回调)
				2.具体表达:
						(1).从语法上来说: Promise是一个内置构造函数
						(2).从功能上来说: Promise的实例对象可以用来封装一个异步操作,并可以获取其成功/失败的值
  -->
<script type="text/javascript">
	/* 
		1.Promise不是回调,是一个内置的构造函数,是程序员自己new调用的。
		2.new Promise的时候,要传入一个回调函数,它是同步的回调,会立即在主线程上执行,它被称为executor函数
		3.每一个Promise实例都有3种状态:初始化(pending)、成功(fulfilled)、失败(rejected)
		4.每一个Promise实例在刚被new出来的那一刻,状态都是初始化(pending)
		5.executor函数会接收到2个参数,它们都是函数,分别用形参:resolve、reject接收
					1.调用resolve函数会:
							(1).让Promise实例状态变为成功(fulfilled)
							(2).可以指定成功的value。
					2.调用reject函数会:
							(1).让Promise实例状态变为失败(rejected)
							(2).可以指定失败的reason。
	*/
	//创建一个Promise实例对象
	const p = new Promise((resolve, reject)=>{
		reject('ok')
	})
	console.log('@',p); //一般不把Promise实例做控制台输出

</script>
</body>
</html>

主要记忆

executor函数,是一个同步回调函数

三种状态 初始化、成功、失败

两个函数 resolve(value) 成功 reject(value)失败 value可以指定生工或失败内容

6.5、Promise基本使用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Promise基本使用</title>
</head>
<body>
	<!-- 
		1. 重要语法
						new Promise(executor)构造函数
						Promise.prototype.then方法

		2. 基本编码流程
					1.创建Promise的实例对象(pending状态), 传入executor函数
					2.在executor中启动异步任务(定时器、ajax请求)
					3.根据异步任务的结果,做不同处理:
								3.1 如果异步任务成功了:
												我们调用resolve(value), 让Promise实例对象状态变为成功(fulfilled),同时指定成功的value
								3.2 如果异步任务失败了:
												我们调用reject(reason), 让Promise实例对象状态变为失败(rejected),同时指定失败的reason
					4.通过then方法为Promise的实例指定成功、失败的回调函数,来获取成功的value、失败的reason
								注意:then方法所指定的:成功的回调、失败的回调,都是异步的回调。

		3. 关于状态的注意点:
					1.三个状态:
								pending: 未确定的------初始状态
								fulfilled: 成功的------调用resolve()后的状态
								rejected: 失败的-------调用reject()后的状态
					2.两种状态改变
								pending ==> fulfilled
								pending ==> rejected
					3.状态只能改变一次!!
					4.一个promise指定多个成功/失败回调函数, 都会调用吗?
						   多个then 或者catch方法,都会接收到异步任务的结果,按照顺序来
	 -->
	<script type="text/javascript" >

		const p = new Promise((resolve,reject)=>{
			//模拟一个异步任务
			/* setTimeout(()=>{
				resolve('我是成功的数据')
			},2000) */

			//真正开启一个异步任务
			const xhr = new XMLHttpRequest()
			xhr.onreadystatechange = ()=>{
				if(xhr.readyState === 4){
					//readyState为4代表接收完毕,接收的可能是:服务器返回的成功数据、服务器返回的错误
					if(xhr.status === 200) resolve(xhr.response)
					else reject('请求出错')
				}
			}
			xhr.open('GET','https://api.apiopen.top/getJoke')
			xhr.responseType = 'json'
			xhr.send()
		})
		
		p.then(
			(value)=>{console.log('成功了1',value);}, //成功的回调-异步
			(reason)=>{console.log('失败了1',reason);} //失败的回调-异步
		)
		console.log('@');

	</script>
</body>
</html>

6.6、封装一个简单的ajax

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>封装一个简单的ajax</title>
</head>
<body>
<script type="text/javascript">

  /*
		定义一个sendAjax函数,对xhr的get请求进行封装:
				1.该函数接收两个参数:url(请求地址)、data(参数对象)
				2.该函数返回一个Promise实例
							(1).若ajax请求成功,则Promise实例成功,成功的value是返回的数据。
							(2).若ajax请求失败,则Promise实例失败,失败的reason是错误提示。
  */
	function sendAjax(url,data){
		return new Promise((resolve,reject)=>{
				//实例xhr
				const xhr = new XMLHttpRequest()
				//绑定监听
				xhr.onreadystatechange = ()=>{
					if(xhr.readyState === 4){
						if(xhr.status >= 200 && xhr.status < 300) resolve(xhr.response);
						else reject('请求出了点问题');
					}
				}
				//整理参数
				let str = ''
				for (let key in data){
					str += `${key}=${data[key]}&`
				}
				str = str.slice(0,-1)
				xhr.open('GET',url+'?'+str)
				xhr.responseType = 'json'
				xhr.send()
			})
	}
	
	const x = sendAjax('https://api.apiopen.top/getJoke',{page:1,count:2,type:'video'})
	x.then(
		(data)=>{console.log('成功了',data);},
		(reason)=>{console.log('失败了',reason);}
	)

</script>
</body>
</html>

6.7、纯回调的方式封装ajax

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>封装一个简单的ajax(纯回调)</title>
</head>
<body>
<script type="text/javascript">

  /*
		定义一个sendAjax函数,对xhr的get请求进行封装:
				1.该函数接收4个参数:url(请求地址)、data(参数对象)、success(成功的回调)、error(失败的回调)
  */
	function sendAjax(url,data,success,error){
		//实例xhr
		const xhr = new XMLHttpRequest()
		//绑定监听
		xhr.onreadystatechange = ()=>{
			if(xhr.readyState === 4){//响应了消息,至于是骂你的还是夸你的就得用status来判断了
				if(xhr.status >= 200 && xhr.status < 300) success(xhr.response);
				else error('请求出了点问题');
			}
		}
		//整理参数
		let str = ''
		for (let key in data){
			str += `${key}=${data[key]}&`
		}
		str = str.slice(0,-1)
		xhr.open('GET',url+'?'+str)
		xhr.responseType = 'json'
		xhr.send()
	}

	sendAjax(
		'https://api.apiopen.top/getJoke',
		{page:1,count:2,type:'video'},
		response =>{
			console.log('第1次成功了',response);
			sendAjax(
				'https://api.apiopen.top/getJoke',
				{page:1,count:2,type:'video'},
				response =>{
					console.log('第2次成功了',response);
					sendAjax(
						'https://api.apiopen.top/getJoke',
						{page:1,count:2,type:'video'},
						response =>{
							console.log('第3次成功了',response);
						}, 
						err =>{console.log('第3次失败了',err);}
					)
				}, 
				err =>{console.log('第2次失败了',err);}
			)
		}, 
		err =>{console.log('第1次失败了',err);}
	)
</script>
</body>
</html>

肉眼可见采用纯回调会发生回调地狱的问题,尽管在Jquery1.5以后实现了PromiseA+规范,但是由于新兴起的axios非常好用,也就不在考虑使用Jquery的Ajax

6.7、常见的包管理器对比

cnpm yarn npm pnpm

cnpm阿里出品,这个东西我们一般是用他的国内镜像。这个东西有一个很大的缺点,cnpm安装的东西他有一个缺点,他会给他建立一个快捷方式,随这你安装更多的包,他的快捷方式会越来越大,这都是不是主要的,问题是他在卸载某个包的时候他会把你安装的所有包都给卸载掉,他又三种卸载包的命令,都存在这种问题。他也没有打算处理。所以不要用它

测试npm、初始化一个项目,包名能起跟主流库一样的名字嘛,不能!那冲突能咋的呀?也不报错啊,有一严重的问题,你自己初始化的包名叫做jquery的时候,就导致你下载不下来真正的Jquery这个库,你本身就是jquery,还怎么下载jquery,但是yarn就没有这个问题 yarn add,yarn的算法比较优秀,他的缓存文件做也不错。用yarn还是比较不错的。下载速度也比较快,目前我电脑上是这么使用包管理器的 yarn的命令,因为yarn他对包的索引啊,遍历啊对比啊,他的速度非常快,用yarn的命令,用cnpm的仓库地址,这俩人配合起来安装包是特别快的,但是个别时候,如果说由于网络状况导致yarn可能不好用,那我顶多用下npm,cnpm那基本上是不会用的

6.8、复习

Ajax跨域问题、同源策略

jsonp解决跨域问题,前端script标签发送get请求不受到同源策略的影响、然后把数据带回来、前端定义函数、后端调用函数

jQuery封装的jsonp

uuid、随机的生成一个字符串,至少在几百年内唯一的这么一个id、一种特殊的算法、所处的地理位置、经纬度、以及当前电脑的时间,内存条的序列号,网卡的mac地址,这些东西给你拼凑,然后经过一个算法生成的

cors解决跨域、浏览器的ajax引擎 xhr得借助ajax引擎,ajax引擎特别听一个人的话那就是同源策略,你打他一顿,下次他不敢拦你了,这是把问题解决了

jquery的jsonp是绕过去了、cors是怎么解决的,你得需要一些特殊的响应头,同源策略并不是限制请求不能发送过去,而是限制的请求不能回来,他的策略就是,他相应数据的时候并不单单把数据响应回来,而是给你的脑门上贴一些特殊的相应头,

Access-Control-Allow-Origin

访问-控制-允许-源

Access-Control-Expose-Headers —能解决简单请求 get post

访问-控制-暴漏-请求头

Access-Control-Allow-Methods --put delete, 复杂请求会发送两次请求,第一次是嗅探请求,也被称为是预请求 options

访问-控制-允许-方法

反向代理工具解决跨域问题

函数对象与实例对象

回调函数

​ 我们定义的,我们没有调用,但是自己执行了

回调函数的分类

​ 同步的回调、主线程上立即执行,不进回调队列(数组遍历相关的回调)

​ 异步的回调、不会立即执行、 会放入回调队列(定时器回调/ajax回调)

js的错误类型/错误的处理

Promise初步认识(Es6)异步编程的新方案,就方案,纯回调 三个状态两个回调、是一个内置的构造函数

作用是封装一个异步任务,构造函数,传入一个执行器函数,封装异步任务,切换Promise状态,.then执行成功和失败的回调

//创建一个Promise实例对象
const p = new Promise((resolve, reject)=>{
		reject('ok')
})
console.log('@',p); //一般不把Promise实例做控制台输出
;