【前端面经】JS-异步解决方案

同步和异步

众所周知, JavaScript是一门单线程的语言, 单线程就意味着同一时间只能执行一个任务, 当前任务执行结束, 才会执行下一个任务. 这种模式的好处就是执行环境比较单纯, 但坏处也很明显, 一旦有某个任务卡住了, 就会导致整个程序阻塞. 为了解决这个问题, JS将任务的执行模式分成了同步(Synchronous)异步(Asynchronous)两种.

更详细的同步异步的执行模式可以参考事件循环

下面我们就来讲讲JS异步编程的几种解决方案.

1.回调函数

回调函数是异步编程的最基本的方法, 它通常作为一个参数传递给另一个函数, 并且在父函数执行完成后执行回调函数

例如:

function logB(){
    console.log("b");
}

function parent(a, callback) {
    console.log(a);
    typeof callback === 'function' ? callback() : return
}

parent('a', logB)

在上面的例子中, 在parent函数中, 如果callback参数传入的是一个函数, 那么在输出形参a之后就会执行callback函数, 上述例子中logB就是作为回调函数传入parent中并执行

在实际开发过程中, 回调函数的使用场景还是很多的, 例如常见的数组遍历方法forEach, 其第一个参数就是回调函数

let arr = [1, 2, 3]
arr.forEach((item) => {
    console.log(item);
})

回调函数的优点是简单易懂, 但其实一旦嵌套起来很不利于代码的维护和可读性. 而且各个部分之间高度耦合, 流程会比较混乱. 最经典就是回调地狱(callback hell).
在实际开发过程中, 经常能遇到一些业务需要先发送一个请求获取数据后, 再根据这个请求的返回结果再发送第二个请求, 第三个请求可能又需要第二个请求的返回结果作为参数, 如此层层嵌套就称之为回调地狱, 这样的代码就很难维护.

ajax('url1', (res1) => {
    console.log(res1)
    ajax('url2+res1', (res2) => {
        console.log(res2)
        ajax('url3 + res2', (res) => {
            console.log(res3)
            ...
        })
    })
})

优点: 简单易懂
缺点: 多层回调函数嵌套时容易混乱, 不利于代码维护和可读性, 容易写出回调地狱

事件监听

这种方式, 异步任务的执行不取决于代码的执行顺序, 而取决于某个事件是否发生.

element.addEventListener('click', ()=> {
    console.log('click')
})

上面这个例子的含义是, 当element被点击时, 就会输出click

  • 优点: 比较容易理解, 并且可以绑定多个事件, 每个事件可以指定多个回调函数, 可以比较好的去耦合, 有利于实现模块化.
  • 缺点: 整个程序变成了事件驱动型, 运行流程很不清晰, 比较难看出主流程, 代码可读性低

Promise

Promise是一种处理异步代码(并且不会陷入回调地狱)的方式

Promise代表一个异步操作, 其有三种状态pending(进行中)fulfilled(已完成)rejected(已失败), 一个Promise对象必然处于这三种状态之一

  • pending: 初始状态, 既没有完成, 也没有被拒绝
  • fulfilled: 操作成功完成
  • rejected: 操作失败

Promise被调用后, 它会以pending开始, 代码会继续往下执行, 而Promise仍处于pending状态, 直到执行完成为止, 最终会以fulfilledrejected结束, 并对应的传给回调函数–then或者catch.
优点: 不仅可以解决回调地狱问题, 而且能够捕获错误并进行处理
缺点: 无法取消Promise

Generator

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同,Generator 最大的特点就是可以控制函数的执行。

语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。
Generator 函数除了状态机,还是一个遍历器对象生成函数。
可暂停函数, yield可暂停,next方法可启动,每次返回的是yield后的表达式结果。
yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。

async/await

本质上async和await是Promise的语法糖, 它可以使得异步代码看起来像同步代码一样

更加详细的Promise可以参考: Promise

总结

  1. JS 异步编程进化史: callbackpromisegeneratorasync/await
  2. async/await 函数的实现,就是将 Generator 函数和自动执行器,包装在一个函数里。
  3. async/await可以说是异步终极解决方案了。

(1) async/await函数相对于Promise, 优势体现在:

  • 处理 then 的调用链,能够更清晰准确的写出代码
  • 并且也能优雅地解决回调地狱问题。
    当然async/await函数也存在一些缺点:
  • 因为 await 将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了 await 会导致性能上的降低,代码没有依赖性的话,完全可以使用 Promise.all 的方式。

(2) async/await函数对 Generator 函数的改进,体现在以下三点:

  1. 内置执行器。

    Generator 函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器。也就是说,async 函数的执行,与普通函数一模一样,只要一行。

  2. 更广的适用性。

    co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)。

  3. 更好的语义。

    async 和 await,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
《java面经-百度准入职老哥整理.pdf》是一份关于百度准入职面试的Java面经整理。这份面经是由百度准入职的老哥整理而成,其中记录了一些面试时可能会遇到的问题以及解答方法。 这份面经对于准备参加百度准入职面试的人来说非常有价值。首先,它列出了一些常见的面试问题,涵盖了Java语言的各个方面,包括基础知识、数据结构与算法、设计模式、多线程、网络编程等等。通过仔细研究和复习这些问题的答案,可以帮助面试者全面了解Java语言的特性和应用。 其次,这份面经还提供了问题的解答思路和方法,帮助面试者理清思路,正确回答问题。这对于很多面试者来说特别有帮助,因为在面试时有时会遇到一些棘手的问题,有了这份面经的指导,面试者可以更好地掌握应对策略。 不过需要注意的是,面经作为一份参考资料,不能完全依赖于它来准备面试。面试官可能会问一些不在面经中列出的问题,因此考生还是需要自己对Java语言有充分的了解,并能够熟练运用。同时,面试官还会关注考生的沟通能力、解决问题的能力以及对新技术的学习和掌握能力。 总体来说,《java面经-百度准入职老哥整理.pdf》是一份非常宝贵的资料,可以帮助面试者对Java面试中可能会遇到的问题有更深入的了解,提供了解答思路和方法。但记住,面试准备还需要多方面的知识积累和实践经验的积累,才能在面试中展现自己的优势。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深海大凤梨_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值