资讯专栏INFORMATION COLUMN

js异步从入门到放弃(实践篇) — 常见写法&面试题解析

Awbeci / 3074人阅读

摘要:前文该系列下的前几篇文章分别对不同的几种异步方案原理进行解析,本文将介绍一些实际场景和一些常见的面试题。流程调度里比较常见的一种错误是看似串行的写法,可以感受一下这个例子判断以下几种写法的输出结果辨别输出顺序这类题目一般出现在面试题里。

前文

该系列下的前几篇文章分别对不同的几种异步方案原理进行解析,本文将介绍一些实际场景和一些常见的面试题。(积累不太够,后面想到再补)

正文 流程调度(schedule)

流程调度,最常见的就是继发并发(或者说串行和并行)两种类型,在日常工作里都很常见。接下来结合实际场景进行说明:

1. 串行执行一系列异步操作,每一步依赖前一步的结果

串行执行的关键是,将每一个异步任务放到前一个异步任务的回调函数里执行

场景:一串连续的动画,每个动画必须等待前一个动画完全执行完,并且如果某个动画执行失败,则不继续执行下一个动画。

代码:

    
    // 这里假定一共要执行5个动画 
    
    // getAnimation 函数模拟执行动画 接收参数i表述动画编号 返回一个promose
    const getAnimation = (i) => new Promise((resolve, reject) => {
        setTimeout(()=>{
            // 随机返回true或者false 
            const isSuccess = Math.random() > 0.5
            console.log(`第${i}个动画执行`)
            if(isSuccess){
                return resolve(isSuccess)
            }
            return reject(isSuccess)
        },1000)
    })

    // 1.promise实现 核心就是嵌套代码
    const serialScheduleByPromise = () => {
        let p = Promise.resolve(true)
        const tasks = []
        for(let i=0;i < 5; i++){
            p = p.then(isSuccess=>{
                if(isSuccess){
                    return getAnimation(i+1)
                }
            }).catch((err)=>{
            return console.log(`执行失败`)
        })
        }
    }
    serialScheduleByPromise()

    // 2.async/await实现
    const serialScheduleByAsync = async () => {
        try{
        for(let i=0;i < 5; i++){
            await getAnimation(i+1)
        }}catch(e){
            console.log(`执行失败`)
        }
    }
    serialScheduleByAsync()

async/await的语法虽然没有多带带解析,但是本质就是前一篇介绍的带自动执行器的generator而已,因此不再赘述
可以看到,async的写法代码更简洁,而且逻辑更清晰,可读性更强。

2. 并行执行所有异步操作,等到所有请求完成后,按照读取请求的顺序输出结果

场景:并发读取5个数据(为了方便 分别编号为1-5),然后按照实际读取顺序结果

    const getDataById = (i) => new Promise((resolve, reject) => {
        // 随机延迟一个时间返回结果,
        const delay = Math.floor(Math.random() * Math.floor(3000)) // 延迟时间可能为 0,1000,2000 毫秒
        setTimeout(()=>{
            return resolve(i)
        }, delay)
    })
    
    // 1.promise实现
    const concurrentScheduleByPromise = ()=>{
        const promises = []
        const result = []
        for(let i = 0;i < 5;i++){
            promises[i] = getDataById(i+1)
            promises[i].then(i=>{
                result.push(i)
            })
        }
        Promise.all(promises).then(()=>{
            result.forEach(id=>{
                console.log(id)
            })
        })
    }
    concurrentScheduleByPromise()

    // async/await实现
    const concurrentScheduleByAsync = () => {
        for(let i = 0 ;i < 5; i++){
            let task = async function (){
                console.log(await getDataById(i+1))
            }
            task()
        }
    }
    concurrentScheduleByAsync()

注意辨析这里concurrentScheduleByAsyncserialScheduleByAsync的区别,关键点是同一个async函数内部的await才是按顺序执行

流程调度里比较常见的一种错误是“看似串行”的写法,可以感受一下这个例子:

    const getPromise = (name) =>new Promise(resolve=>{
        setTimeout(()=>{
            console.log(name)
            resolve(name)
        },1000)
    })
    
    // 判断以下几种写法的输出结果 
    Promise.resolve().then(getPromise("1a")).then(getPromise("1b")).then(getPromise("1c")) 
    Promise.resolve().then(()=>getPromise("2a")).then(()=>getPromise("2b")).then(()=>getPromise("2c")) 
    Promise.resolve().then(getPromise("3a").then(getPromise("3b").then(getPromise("3c")))) 
    Promise.resolve().then(()=>getPromise("4a").then(()=>getPromise("4b").then(()=>getPromise("4c")))) 
辨别输出顺序

这类题目一般出现在面试题里。

1. 基础-区分不同任务类型
    console.log(1)
    new Promise(resolve => {
        console.log(2)
        setTimeout(() => {
            console.log(10)
        }, 10)
        resolve()
        console.log(3)
    }).then(() => {
        console.log(5)
    })

    setTimeout(() => {
        console.log(7)
        Promise.resolve().then(() => {
            console.log(9)
        })
        console.log(8)
    })

    Promise.resolve().then(() => {
        console.log(6)
    })
    console.log(4)
    // 输出 1 2 3 4 5 6 7 8 9 10
2. 复杂-加入浏览器render



    
outer
inner

这类问题实质上就是辨析异步任务队列类型,详细内容和解析可以直接看js异步从入门到放弃(三)- 异步任务队列(task queues)。

小结

这篇文章主要是给这个系列做个简单的收尾,多带带纯异步的问题难点其实也不多,偷个懒,后面想到了再补上。

如果觉得写得不好/有错误/表述不明确,都欢迎指出
如果有帮助,欢迎点赞和收藏,转载请征得同意后著明出处。如果有问题也欢迎私信交流,主页有邮箱地址
如果觉得作者很辛苦,也欢迎打赏~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104654.html

相关文章

  • 前端资源系列(4)-前端学习资源分享&amp;前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0
  • javasscript - 收藏集 - 掘金

    摘要:跨域请求详解从繁至简前端掘金什么是为什么要用是的一种使用模式,可用于解决主流浏览器的跨域数据访问的问题。异步编程入门道典型的面试题前端掘金在界中,开发人员的需求量一直居高不下。 jsonp 跨域请求详解——从繁至简 - 前端 - 掘金什么是jsonp?为什么要用jsonp?JSONP(JSON with Padding)是JSON的一种使用模式,可用于解决主流浏览器的跨域数据访问的问题...

    Rango 评论0 收藏0
  • Deep in JS - 收藏集 - 掘金

    摘要:今天同学去面试,做了两道面试题全部做错了,发过来给道典型的面试题前端掘金在界中,开发人员的需求量一直居高不下。 排序算法 -- JavaScript 标准参考教程(alpha) - 前端 - 掘金来自《JavaScript 标准参考教程(alpha)》,by 阮一峰 目录 冒泡排序 简介 算法实现 选择排序 简介 算法实现 ... 图例详解那道 setTimeout 与循环闭包的经典面...

    enali 评论0 收藏0
  • 前端面试之路二(javaScript基础整理)

    摘要:在标签中添加属性,本质上是跟在标签里面写属性时一样的,所以属性值最终都会编译为字符串类型。这个节点包括很多,比如,以及一些方法等方法。一个对象有很多,该集合名字为,里面有其他以及,里面有很多。 一、变量类型和计算 JS中使用typeof能得到哪些类型 变量类型 值类型:变量本身就是含有赋予给它的数值的,它的变量本身及保存的数据都存储在栈的内存块当中 引用类型:引用类型当然是分配到...

    AbnerMing 评论0 收藏0
  • 前端最实用书签(持续更新)

    摘要:前言一直混迹社区突然发现自己收藏了不少好文但是管理起来有点混乱所以将前端主流技术做了一个书签整理不求最多最全但求最实用。 前言 一直混迹社区,突然发现自己收藏了不少好文但是管理起来有点混乱; 所以将前端主流技术做了一个书签整理,不求最多最全,但求最实用。 书签源码 书签导入浏览器效果截图showImg(https://segmentfault.com/img/bVbg41b?w=107...

    sshe 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<