通过回调函数获取函数的执行结果:
1、sum定义三个形参分别为a、b、cb(回调函数callback)。给sum传递三个实参分别为123、456、function函数, 则 cb 即为第三个参数;
2、调cb()就是在调function(){ }这个函数,将a+b作为回调函数的参数传递给function(){ },定义形参result接收这个变量;
3、将result作为结果输出。
function sum(a,b,cb){
cb(a+b)
}
sum(123,456,function(result){
console.log(result)
})
注:下述的return是匿名函数的返回值,并不是sum的返回值
function sum(a, b, cb) {
setTimeout(() => {
return a + b
}, 1000)
}
所以需要通过回调函数来返回,即为回调函数的作用。
function sum(a, b, cb) {
setTimeout(() => {
cb(a + b)
}, 1000)
}
node.js 通过异步方式解决同步的问题
什么是异步?
一段代码执行不会影响到其他程序
异步的问题?
异步的代码无法通过return来设置返回值
特点?
1、不会阻塞其他代码执行 2、需要通过回调函数来返回结果
基于回调函数的异步带来的问题?
1、代码的可读性差 2、可调式性差
解决问题:
需要一个东西,可以代替回调函数来给返回结果。Promise!!!
Promise 是一个可以用来存储数据的对象
Promise存储数据的方式比较特殊,这种特殊方式使得Promise可以用来存储异步调用的数据。
注:现实生活:1、点菜 2、厨师做菜 3、吃。
异步调用必须要通过回调函数来返回数据,当我们进行一些复杂的调用时,会出现“回调地狱”
Promise:可以帮助解决异步中回调函数的问题,是一个用来存储数据的容器,它拥有着一套特殊的存储数据的方式,这个方式使它可以存储异步调用的结果。
创建Promise时,构造函数中需要函数作为参数。
const promise = new Promise(() => {})
Promise构造函数的回调函数,它会在创建Promise时调用,调用时会有两个参数传递进去
const promise = new Promise((resolve, reject) => {}
resolve和reject是两个函数,通过这两个函数可以向Promise中存储数据;
resolve在执行正常时存储数据,reject在执行错误时执行数据。
const promise = new Promise((resolve, reject) => {
reject("哈哈") //错误时存储,需抛出异常throw new Error("哈哈,出错了")
resolve("resolve返回的数据")
})
console.log(promise)
通过函数来向Promise中添加数据,好处就是可以用来添加异步调用的数据;
第一个匿名函数在2秒后执行,第二个匿名函数在3秒后执行,“哈哈”被存入到resolve中。
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("哈哈")
}, 2000)
})
setTimeout(() => {
console.log(promise)
}, 3000)
从Promise中读取数据
可以通过Promise的实例方法then来读取Promise中存储的数据
then需要两个回调函数作为参数,回调函数用来获取Promise中的数据
通过resolve存储的数据,会调用第一个函数返回,可以在第一个函数中编写处理数据的代码
通过reject存储的数据 或者出现异常时,会调用第二个函数返回数据,可以在第二个函数中编写处理异常的代码
注:resolve和reject是Promise创建的,用来存数据的
result和reason是自己创建的,用来取数据的
const promise = new Promise((resolve, reject) => {
//throw new Error("哈哈,出错了")
//resolve("resolve返回的数据")
reject("reject返回的数据")
})
promise.then((result) => {
console.log("1", result);
}, (reason) => {
console.log("2", reason);
})
Promise中维护了两个隐藏属性:PromiseResult PromiseState
PromiseResult:用来存储数据
PromiseState:记录Promise的状态(三种状态)
注:state只能修改一次,修改以后永远不会在变
pending (进行中)
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("哈哈")
}, 2000)
})
console.log(promise2);
fulfilled (完成) 通过resolve存储数据
const promise2 = new Promise((resolve, reject) => {
resolve("哈哈")
})
console.log(promise2);
rejected (拒绝,出错了) 出错了或通过reject存储数据时
const promise2 = new Promise((resolve, reject) => {
reject("哈哈")
})
console.log(promise2);
流程:
当Promise创建时,PromiseState初始值为pending
当通过resolve存储数据时,PromiseState 变为fulfilled,PromiseResult变为存储的变量
当通过reject存储数据或出错时,PromiseState 变为rejected,PromiseResult变为存储的变量 或 异常对象
当我们通过then读取数据时,相当于为Promise设置了回调函数:
注:如同DOM中为响应函数绑定事件
如果PromiseState变为fulfilled,则调用then的第一个回调函数来返回数据;如果PromiseState变为reject,则调用then的第二个回调函数来返回数据。
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("哈哈")
}, 2000)
})
promise2.then(result => {
console.log(result);
}, reason => {
console.log("出错了");
})
catch()
catch() 用法和then类似,但是只需要一个回调函数作为参数
catch()中的回调函数只会在Promise被拒绝时才会调用
catch()相当于 then(null,reason =>{})
注:catch() 就是一个专门处理Promise异常的方法
const promise2 = new Promise((resolve, reject) => {
reject("哈哈")
})
promise2.catch(reason =>{
console.log(2222);
})
finally()
无论是正常存储数据还是出现异常,finally总会执行,但是finally的回调函数中不会接收数据
finally()通常用来编写一些无论成功与否都要执行的代码
const promise2 = new Promise((resolve, reject) => {
resolve("哈哈")
//reject("哈哈")
})
promise2.finally(() => {
console.log("没有什么能够阻挡");
})
回调地狱:
function sum(a, b, cb) {
setTimeout(() => {
cb(a + b)
}, 1000)
}
const result = sum(123, 456, (result) => {
sum(result, 7, (result) => {
sum(result, 8, (result) => {
sum(result, 9, (result) => {
sum(result, 10, (result) => {
console.log(result);
})
})
})
})
})
解决回调地狱问题
定义一个异步函数sum()
将结果a+b通过resolve存储到Promise中
注:当返回值是Promise对象时不用接收返回值
function sum(a, b) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a + b)
}, 1000)
})
}
sum(123,456).then((result)=>{
console.log(result)
})
注:promise中的 then (return new Promise()) ,catch (return new Promise()) , finally ,这三个方法都会返回一个新的promise;Promise中存储的是回调函数的返回值 但是 finally 的返回值不会存储到新的Promise中
p2中回调函数的返回值会成为新的promise中的result
then中的代码是异步调用
const promise = new Promise((resolve, reject) => {
resolve("每周一到周五19点");
})
const p2 = promise.then((result) => {
console.log("回调函数", result);
return "锄禾日当午"
})
setTimeout(() => {
console.log(p2);
}, 1000)
function sum(a, b) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a + b)
}, 1000)
})
}
sum(123, 456)
.then(result => result + 7)
.then(result => result + 8)
.then(result => result + 9)
.then(result => console.log(result))
无异常会跳过catch,只执行then
const promise = new Promise((resolve, reject) => {
resolve("每周一到周五19点");
})
promise
.then(r => "哈哈")
.catch(r => console.log("异常处理",+r))
.then(r => console.log("第二个then",r))
有异常会跳过第一个catch之前的所有then,只执行catch和之后的then
const promise = new Promise((resolve, reject) => {
reject("每周一到周五19点");
})
promise
.then(r => console.log("第一个then",r))
.catch(r => console.log("异常处理",r))
.then(r => console.log("第二个then",r))
输出结果:
undefined 是.catch返回的新的promise的值
异常处理 每周一到周五19点
第二个then undefined
也可也设置新promise的返回值
const promise = new Promise((resolve, reject) => {
reject("每周一到周五19点");
})
promise
.then(r => "哈哈")
.catch(r => {
console.log("异常处理", r)
return "嘻嘻"
})
.then(r => console.log("第二个then", r))
输出结果:
嘻嘻是catch中新的promise的返回值
异常处理 每周一到周五19点
第二个then 嘻嘻
注:对Promise进行链调用时,后边的方法(then和catch)读取的是上一步的执行结果,如果上一步的执行结果不是当前想要的结果,则跳过当前的方法
在promise中,后面的catch处理前面的错误
promise
.then(r => "哈哈")
.catch(r => {
throw new Error("报个错玩")
console.log("异常处理", r)
return "嘻嘻"
})
.then(r => console.log("第二个then", r))
.catch(r =>{
console.log("出错了");
})
注:只需要将catch写在最后即可