同异步

95 阅读3分钟

同步异步

同步

一件一件往下做,需要等完成后,才能进入下一件,会有堵塞状态

在浏览器运行中有大量网络请求,而网络资源啥时候返回,时间不可估,难道也等着、啥都不干?

于是,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

  1. 创建promise对象

    利用构造函数,将异步函数 转为 Promise对象,传入resolve和reject函数,分别调用res/rej函数,接收成功/失败时返回的数据

  2. 链式调用

    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 思否

第11节:异步编程_哔哩哔哩_bilibili

generator

事件循环机制

js是单线程语言,一次只做一件事

执行顺序:同步->process.nextTick->异步(微->宏)->setImmediate(当前事件循环结束就执行)

异步=宏任务+微任务,常见的异步有:定时器、ajax、事件绑定函数、回调函数、async await、promise

  • 宏任务:计时器setTimeout/setInterval、ajax、读取文件
  • 微任务:promise.then

事件轮循.png