什么是JS中的回调函数?
回调函数:
运行某个函数实现某个功能的时候,传入一个函数作为参数,当发生某件事情的时候,会执行该函数 这个函数参数就是回调函数
回调地狱:
某个异步操作需要等待之前的异步操作完成,无论回调是事件还是其他函数,都会陷入不断的嵌套
通过回调函数异步操作 某个异步操作要等待别的操作对他的结果,这种联系的处理,会让代码的复杂度急剧增加
promise
promise简介
ES官方参考了大量的异步场景,总结出了一套异步通用的模型,这套模型可以覆盖几乎所有的异步场景
ES6中增强的功能,ES为了兼容以前的版本,以前旧的写法并没有抛弃,针对这些场景推出了新的API,这套API对异步的处理,变得更为简洁
将某一件事情可以发生异步操作的时候,分为了2个阶段 unsettled 和 settled
unsettled未决阶段
settled已决阶段
事情总是从 未决阶段逐步发展到已决阶段,并且,未决阶段拥有控制通往已决阶段的能力
es6将程序分为了三种状态 pending resolved rejected
pending:挂起(等待) 处于未决阶段,表示事情还是在挂起,最后的结果没有出来
resolved:已处理 处于已决阶段,表示整个事情已经出现结果,并且可以按照正常的逻辑进行下去的结果
rejected:已拒绝 处于已决阶段,表示整个事情已经出现结果,并且是一个无法按照正常逻辑进行下去的结果
未决阶段有权利决定事情的走向,未决阶段可以决定事情走向最终的状态
把事情推向resolved 状态的过程,可能会传递一些数据
把事情推向resolved 状态的过程,可能会传递一些数据,这些数据一般为错误信息
无论是哪个阶段还是状态,都是不可逆的
当事情已经到达已决阶段后,通常要进行后续的处理,不同的已决解决,决定了不同的后续处理
resolved 这是一个正常的已决状态,后续处理表示为 thenable
rejected 这是一个非正常的已决状态,后续处理表示为 catchable
后续的处理可能会有多个,因此会形成任务队列,这些后续处理会按照顺序,当达到对应的状态后依次执行
Promise 的方法
是异步编程的一种解决方法,其实是一个构造函数 自己身上有all.reject,resolve 这几个方法 ,原型上有then,catch等方法
语法:
只要new Promise()就可以,并且接受一个函数,该函数里面会执行resolve()方法,表示异步调用成功时执行,reject()表示异步调用失败时候调用
未决阶段
通过调用resolve函数将promise推向已决阶段的resolve状态
通过调用reject函数将promise推向已决阶段的reject状态通常使用throw
resolve 和 reject 只能使用一个,如果使用了多个,也只有第一个有用
传递参数只能有一个,表示推向状态的数据
resolve({})或者reject(456)
const pro = new Promise((resolve,reject) => {
resolve(456)
reject(123)//throw 作用一样都是推向失败
})
then方法
pro.then(data=>{
thenable函数,promise已经是已决阶段,resolve状态
},err => {
catchable函数 reject状态
})
catch()方法
pro.catch(err => {
catchable函数 reject状态
console.log(err)
})
Promise 特点
1.未决阶段的处理函数是同步的,会立即执行
2.如果当前的promise是未决的,得到的新的promise是挂起状态
3.在未决阶段的处理函数中,如果发生未补获的错误,会将状态推向rejected,并且会被catchable捕获
4.一旦状态推向了已决阶段,无法再去做任何的改变
5.thenable和catchable函数是异步的,就算会立即执行,也是会加入等待队列中,加入微队列
6.pro.then可以只添加thenable函数,pro.catch可以单独添加catchable函数
7.如果前面的promise的后续处理,返回的是一个promise,则返回的promise状态和后续处理返回的promise状态保持一致
8.Promise并不是消除回调,只是让回调变得更简单,变更可控
Promise 原型成员(实例成员)
1.then(data => {},err => {})
注册一个后续处理函数,当promise为resolved状态是运行该函数,当promise为rejected状态是运行该函数的第二个参数
2.catch() 注册一个后续处理函数,当promise为rejected状态是运行该函数,习惯把失败写在catch中
3.finally() ES2018出来的,没有参数的,当promise为已决时运行该函数 先写先执行 后写后执行
const pro = new Promise((resolve,reject) => {
resolve(1)
})
pro.finally(() => {
console.log('finally')
})
pro.then(result => {
console.log('then',result * 2)
})
Promise构造函数成员(静态成员)
1.resolve()
const pro = Promise.resolve(1)
//等同于
// 推向了完成阶段的成功状态
const pro = new Promise((resolve,reject) => {
resolve(1)
})
2.reject()
const pro = Promise.reject(1)
//等同于
//推向了完成阶段的失败状态
const pro = new Promise((resolve,reject) => {
reject(1)//throw 作用一样都是推向失败
})
特殊情况:如果传递的是Promise,则直接返回传递的Promise对象(原封不动的)
const pro = new Promise((resolve,reject) => {
resolve(123)
})
const pro2 = Promise.resolve(pro)
console.log(pro2 === pro) true
3.all(arr) 这个方法会返回一个新的promise对象,如果里面所有的promise对象都成功才会触发,
一旦有一个失败,则该promise对象为失败
4.ace(arr) 当参数中的任意一个promise对象完成时候,就马上回去使用完成的这个
promise对象的结果,不管这个结果成功还是失败
在ES2016中 新增了两个关键字 async await 为了去简化promise的写法的
async 简化promise创建的 声明一异步任务(async function 对象)
用于去修饰函数(函数声明和函数表达式),放在函数的开始位置,被修饰的函数一定返回一个promise对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。
async function test(){
//return 123;//resolve成功的数据
throw 123//reject失败的数据
}
const pro = test();
console.log(pro)
//等同于
const pro = new Promise((resolve,reject) => {
resolve(123);
reject(123);
}
await 等待 (指的是等待一个异步任务执行完成的结果) await 必须出现在async函数中
function test1(){
return new Promise((resolve,reject) => {
resolve(123)
})
}
function test2(){
return new Promise((resolve,reject) => {
test1().then(data => {
const result = data;
console.log(result);
resolve()
})
})
}
test2()
// 等同于
async function test1(){
return 123;
}
async function test2(){
const result = await test1(); // test1()被async修饰的函数 被当作
console.log(result)
}
test2()
正常情况下,await命令后面是一个 Promise 对象,返回Promise对象的结果。如果await的表达式不是Promise,则会对包装一个promise继续按照规则执行
await使用注意点
1.正常情况下await命令后面修饰的Promise对象,返回Promise对象的结果可能是rejected 错误数据,就不会执行await语句,所以最好把await命令放在try…catch代码块中。
2.await命令只能用在async函数之中,如果用在普通函数,就会报错。