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实例做控制台输出