JS异步问题及常见的异步场景分析

前言

异步问题是我们在学习JavaScript过程中需要关注的一个重点。但是据我观察,目前的各种资料还是以介绍异步问题的解决方案(即,期约、异步函数等异步编程方案)为主,对于异步问题本身讨论较少。所以在这里我尝试按照自己的理解对异步问题做一个提纲挈领的总结,方便自己后续更好的去学习理解各种异步编程方案。

一、异步问题

1.什么是异步问题?

异步问题,即 同步任务依赖异步资源的问题

由于JS的单线程事件循环机制,导致程序中的同步任务一定是在异步任务之前执行的。但是在某些情况下,某些同步任务又依赖于异步任务中所“生产”的资源,其需要在某些异步任务之后执行,因此就与JS本身的机制产生了冲突。这种冲突就是异步问题。解决冲突的方案就是异步编程方案

2.异步编程方案与"逆异步"

(1) 异步编程方案所实现的效果

异步编程方案可以帮助我们解决异步问题。也就是说通过异步编程方案,我可以实现如下的效果:

当某个异步任务执行完毕后,可以“通知”另一个同步任务执行,并且这个同步任务可以使用异步任务所生产的资源。

(2) 常用的异步编程方案

  1. 回调函数
  2. 期约Promise
  3. 异步函数 async/await

(3) 什么是逆异步?

"逆异步" 是我自己总结的一个概念 , 它其实就是上面写到的"异步编程方案所实现的效果"。

二、异步场景

1.什么是异步场景?

异步场景就是指我在实际工作中会面临异步问题的场景,或者说在实际工作中需要实现“逆异步”的场景。更准确的说异步场景就是异步资源传递的场景。

根据实际工作中的经验,我总结了异步场景的核心概念,与异步场景的几个常用范式,后面我会 一 一 介绍。

2.异步场景的核心概念

异步场景的核心概念我总结为“两角色,一核心”

(1)两角色——生产者和消费者

在异步场景中有两种角色:

  • 异步资源生产者 , 指能够获取延迟资源的异步任务
  • 异步资源消费者, 指依赖延迟资源的任务

(2)一核心—— 同步与异步的连锁

连锁是指 生产者获取到异步资源后,通知消费者使用的机制。连锁是连接同步代码与异步代码的桥梁,也是所以异步编程方案所要解决的核心问题。

3.常见的异步场景

(1)基础场景

基础场景就是有一个生产者和一个消费者,当生产者获取到异步资源后传递给消费者,消费者消费异步资源。

基础场景是所有异步场景的基础,也是实际工作中最常遇到的情况。例如:需要将请求到的某个数据打印出来:


let r = await fetch('/bar');
console.log(r);

在上面的这个案例中 fetch('/bar')就是生产者;console.log(r) 就是消费者 ;变量 r就是异步资源;

fetch前的await关键字就可以看做是“连锁机制”,它代表这里使用了 "异步函数 async/await" 这一异步编程方案。

(2)失败处理场景

失败处理场景则是指这样一种情况,生产者生产资源并不一定会成功,有时也会出现生产失败的情况,这时候就需要有两个消费者,一个是生产成功时的消费者,一个是生产失败时的消费者。

这个时候可能有一个疑问了,既然都生产失败了,那么就表示原本应该产出的资源不存在了,那么失败的消费者又能消费什么呢?

实际上生产失败不代表没有产出,例如生产失败了会抛出错误,这个错误就是失败时的资源,甚至生产失败这个消息本身就是一种资源。

示例:

需要将请求到的数据打印出来,但是请求有可能失败,失败的时候会返回失败原因,此时需要将失败原因打印出来。


try{
	let r = await fetch('/bar');
  console.log(r);
}catch(e){
  console.log(e)
}

在上面的示例中console.log(r)就是生产成功时的消费者;console.log(e)就是生产失败时的消费者。变量r是生产成功时产出的资源;变量e则是生产失败时产出的资源。

(3)异步任务串行场景

异步任务串行场景是指,一个生产者在进行资源生产者需要依赖另一个生产者所生产的资源。即一个对象身上同时具备生产者和消费者两种角色的情况。

因此如果面临几个异步任务需要按照一定的顺序串行的情况,也要通过异步编程方案实现,这其实就是“异步代码的同步化”。

示例:

现在需要请求数据B,然后将数据B打印出来,但是在请求数据B时又必须以数据A作为参数,因此就需要先请求数据A,在获取到数据A后再以其为参数请求数据B,最后再打印数据B。


let RA = await fetch('/bar');
let RB = await fetch(`/foo?value=${RA}`);
console.log(RB);

在上面的示例中fetch('/bar')就是生产者A;fetch(`/foo?value=${RA}`)就是生产者B(实际也是消费者);console.log(RB)就是与生产者B关联的消费者。变量RA是资源A;变量RB是资源B。

(4)异步任务组合场景

异步任务组合场景就是指一个消费者需要消费几个生产者所生产的资源的情况。

示例:

现在需要请求A、B、C三个数据,当这三个数据都请求到了之后再打印一句话“数据初始化完成”。

await Promise.all([
  fetch('/bar'),
  fetch('/foo'),
  fetch('/dialog')
]);

console.log('数据初始化完成');
  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值