同步异步
同步
一件一件往下做,需要等完成后,才能进入下一件,会有堵塞状态
在浏览器运行中有大量网络请求,而网络资源啥时候返回,时间不可估,难道也等着、啥都不干?
于是,js设计出异步,即发起一个网络请求时,先不管去干别的,啥时候返回结果啥时候再说,这样就保证了网页流程的正常运行
异步
异步事件:一件需要过段时间才知道结果的事(如怀胎)
先执行a事件的一部分,然后跳过执行b事件,到了a事件结果/时间点,继续执行a的后续代码
优点:实现了分工合作,更效率
让看似同步的代码完成js异步请求
回调函数callback
解决了获取异步数据问题(原因:函数中return拿不到)
callback是作为一个参数传递在另一个函数中
- 举例:函数a在函数b中当作参数传入,调用b传入一个函数类型的参数才会执行a,此时函数a就叫做callback回调函数
function tea(fn){
setTimeout(()=>{
fn('奶茶')
},2000)
}
tea(function(data){
console.log(data)
})
回调地狱
假设我需要执行多个异步请求,但又希望他们按顺序执行,于是使用嵌套
function tea(fn){
setTimeout(()=>{
fn('奶茶')
},2000)
}
function pot(fn){
setTimeout(()=>{
fn('火锅')
},1000)
}
//回调地狱——做完一件做下一件,层层嵌套
//当有n个嵌套时,且有if/for等逻辑语句时,代码会变复杂
tea(function(data){
console.log(data)
pot(function(data){
console.log(data)
})
})
缺点:多层嵌套,产生回调地狱,不利于代码维护性
Promise对象
解决回调地狱问题,舍弃了callback方法,而是采用resolve和reject函数
Promise.then和catch
-
创建promise对象
利用构造函数,将异步函数 转为 Promise对象,传入resolve和reject函数,分别调用res/rej函数,接收成功/失败时返回的数据
-
链式调用
then()接收成功,catch()捕获异常;使用多个then时,需要return一个promise对象
let tea=new Promise((res,rej)=>{
setTimeout(()=>{
//调用res/rej函数
let flag=true
if(flag){
res('奶茶')
}else{
rej('奶茶获取失败')
}
},1000)
})
let pot=new Promise((res,rej)=>{
同上
})
tea.then((data)=>{//res成功
console.log(data)
//返回一个promise对象,提供给后面的then使用
return pot
}).then((data)=>{
console.log(data)
}).catch((err)=>{//rej失败
console.log(err)
})
若干个then串联后,通常在最后加一个.catch捕获异常,这样做的好处是:
- 程序看起来更简洁,是一个串联的关系,没有分支
- 看起来像try-catch的样子,更好理解
Promise.all和Promise.race
接收一个包含多个promise对象的数组参数
// 全部都被读取完,才做下一步操作(一起跑)
Promise.all([res1, res2]).then(datas => {
// 接收一个数组,依次包含了多个promise返回的内容
console.log(datas[0])
console.log(datas[1])
})
// 只要读取了任意一个,就进行下一步操作(跑得快)
Promise.race([result1, result2]).then(data => {
// data 即最先执行完成的 promise 的返回值
console.log(data)
})
async await
promise的语法糖,让代码看起来更像同步,方便维护
promise1、promise2已定义好
//async加在函数前
let getGood=async function(){
//await后加promise对象
let pot=await promise1
console.log(pot)
let tea=await promise2
console.log(tea)
}
getGood()
该写法缺点:当异步请求里存放的是time相同的定时器时,会一起触发
解决:promise定义写在async中
javascript - async 函数里有多个 await 的执行顺序? - SegmentFault 思否
generator
事件循环机制
js是单线程语言,一次只做一件事
执行顺序:同步->process.nextTick->异步(微->宏)->setImmediate(当前事件循环结束就执行)
异步=宏任务+微任务,常见的异步有:定时器、ajax、事件绑定函数、回调函数、async await、promise
- 宏任务:计时器setTimeout/setInterval、ajax、读取文件
- 微任务:promise.then