Cuando setTimeout encuentra un retraso en la red

Como todos sabemos, setTimeout generalmente se usa para el procesamiento de demoras, pero cuando la velocidad de la red del usuario es más lenta que la demora establecida por setTimeout, causará una serie de errores impredecibles...

Por ejemplo, la pila de enrutamiento de la página actual es A -> B. Después de realizar una serie de operaciones en la página B, se debe devolver la página A. La interfaz de usuario de la página A debe mostrarse de acuerdo con el resultado de la operación de la página B. página; por ejemplo, la página B tiene dos botones. Al hacer clic en ellos volverá a la página A, pero al hacer clic en el primero aparecerá una ventana emergente de Diálogo, pero al hacer clic en el segundo botón no lo hará.

¿Cómo hacer frente a este requisito?

1. Usar EventBus

Lo primero que viene a la mente es usar EventBus. Cuando se hace clic en el primer botón, se envía un evento para notificar a A router.back()después de , y luego la página A escucha este evento, y aparece el cuadro de diálogo después de escuchar el evento.

Por brevedad, veamos el efecto imprimiendo el registro:

// B页面
function goBack1() {
  router.back()
  console.log("page B back");
  $bus.emit("showDialog", {});
}

// A 页面
$bus.on("showDialog", () => {
  console.log("收到 showDialog 事件");
});

onMounted(() => {
  console.log("page A onMounted");
});
复制代码

Esto parece no ser un problema, pero ignore un punto, router.back()en realidad es asíncrono, por lo page B backque page A onMountedse imprimirá primero, y el registro que escucha el evento showDialog tampoco se imprime:

page B back
page A onMounted
复制代码

Porque antes de que la página A escuche el evento, el evento ya se ha emitido y no hay posibilidad de consumirlo.

En este momento, pensará que si router.back()es asíncrono, solo agregue un awaitno . Veamos la definición de espalda:

back()El método pushno replacedevuelve una Promesa como y , por lo que incluso awaitanteponerlo no ayuda, como se indicó anteriormente.

Ejemplo, EventBus + setTimeout

Dado que back()no es posible enviar el eventbus inmediatamente después, ¡usted es lo suficientemente inteligente como para pensar que agregar un retraso al eventbus lo resolverá!

function goBack1() {
  router.back();
  console.log("page B back");
  setTimeout(() => {
    $bus.emit("showDialog", {});
  }, 200)
}
复制代码

El retraso es de milisegundos 200. La página debe cargarse dentro de los milisegundos 200. Mire el registro.

page B back
page A onMounted
收到 showDialog 事件
复制代码

Efectivamente, este requisito se completó con éxito y salí feliz del trabajo.

过了两天,测试同事跟你提了个 bug,说从 B 页面返回 A 之后,没有弹出弹框。你不信,亲自在页面上试了试,没问题呀!

跟测试一顿 battle 后,发现他那里的确没弹出弹框。你的小脑袋瓜子飞速运转,问题到底出在那里?一样的代码,为什么不同人运行的效果不一致,难道是人品问题……

突然灵机一动,唯一的变量是网速!

假如 A 页面逻辑很复杂,要加载很多资源,一般网速快的话,200 毫米内是肯定可以初始化完成的,但是如果用户网速特别慢, slow 3G 时代,200毫秒页面不一定能初始化完成,也就会出现发送 eventbus 在监听之前,导致没有监听到的结果。

那增加延迟时间呢?其实不是时间问题,因为不知道用户的网络到底有多慢,即使设 5秒也不一定绝对安全,且太长了会影响用户体验。所以这种方法不可取,不确定性因素太多。

三、最优解

有人说可以用 vuex,从 B 点第一个按钮返回时,在vuex中记录一个变量,A页面读取这个变量判断该展示什么逻辑。这种方式其实也不保险,变量什么时候重置呢?总会有各种极端情况绕过你设置的重置条件。维护中间状态,易出错且成本高。

那将 A 页面做路由缓存呢?首先业务场景要求不能缓存,其次并不能解决不同方式返回处理不同逻辑的需求。

最稳妥的方法是不要用 back(),用 replace()并且在 url 上带上参数,A 页面读取 url 上的参数根据不同状态做出不同动作,一个状态对应确定的一个动作,不管网速如何变化,url 是确定的,就能得到确定的结果。

Supongo que te gusta

Origin juejin.im/post/7085166060491505701
Recomendado
Clasificación