Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

172
Visualizações
Observable obtiene el valor incorrecto cuando usa el operador from con una promesa después de actualizar inmediatamente ese valor en otra promesa

Tengo un observable que escucha los cambios de ruta :) También tengo una promise que borra mi almacenamiento local y cuando termina, cambio inmediatamente la ruta, pero mi switchMap/switchMapTo dentro de mi observable de cambio de ruta obtiene el valor anterior... ¿por qué sucede esto? ¿suceder?

He intentado muchas formas de resolver esto: encontré dos que funcionan :) Pero deseo entender por qué funcionaron. ¿Alguien podría ayudar? ¿Es esto algo relacionado con problemas hot/cold observables ? ¿Quizás algo con el event loop ? Realmente no lo sé :)

 this.storageService.clear().then((_) => { // this was successful!! And it was checked - user is deleted :) // now change the route and trigger the observable below :) }); this.router.events.pipe( filter((e: Event): e is NavigationEnd => e instanceof NavigationEnd) /* switchMap in here to get the user! Options 1 + 2 show that the user info exists!! Although I know for sure that it was deleted. Option 3 + 4 work. */ // 1) switchMapTo(from(this.storageService.getAsync<IUser>('user'))), // 2) switchMapTo(this.storageService.getAsync<IUser>('user')), // 3) switchMap(async (_) => { // const y = await this.storageService.getAsync<IUser>('user'); // return y; // }), // 4) switchMapTo(defer(() => this.storageService.getAsync<IUser>('user'))), ); // Question edited for extra information - this is the getAsync function async getAsync<T>(key: string) { const result: GetResult = await Storage.get({ key }); return JSON.parse(result.value) as T; }
over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Ejecución ansiosa vs perezosa

Esto sucede porque las promesas son ansiosas y las observables son perezosas. Es decir, un observable no hace nada hasta que se suscribe, mientras que una promesa intentará resolverse a sí misma desde el momento en que se define.

Así es como lo escribiría para resolver este problema de la manera más directa:

 this.router.events.pipe( filter((e: Event): e is NavigationEnd => e instanceof NavigationEnd), switchMap(_ => this.storageService.getAsync<IUser>('user')) );

Actualizar:

Por supuesto, no solo el código asíncrono (como las promesas y los observables) puede tener una semántica de evaluación ansiosa/perezosa. El código síncrono regular puede tener los mismos problemas. Dado que podría ser más fácil comprender el problema en un contexto síncrono, crearé algunos ejemplos a continuación que exploran esto sin usar promesas u observables.


Considere este código no observable:

En este primer ejemplo tenemos una función addNumbers que hace el trabajo de sumar dos números por ti. Está ansioso, por lo que hará el trabajo de inmediato y luego devolverá un valor una vez invocado. Puede ver que en la línea 5, c() será igual a 8. 3 y 5 se suman en la línea 6 y luego se imprimen en la línea 8

 function addNumbers(a, b){ const answer = a + b; return () => answer; } const c = addNumbers(3, 5); console.log("This should be an 8:", c());

En el siguiente ejemplo, tenemos una función muy similar, pero es perezosa. Recuerda los números que le diste pero en realidad no suma los números hasta que algo lo invoca. En este caso, c debe invocarse c() antes de que el 3 y el 5 se usen de alguna manera. 5 y 3 no se suman hasta la línea 7.

 function addNumbers(a, b){ return () => a + b; } const c = addNumbers(3, 5); console.log("This should be an 8:", c());

Consecuencias perezosas vs ansiosas

Considere estos dos ejemplos. Si comprende por qué imprimen valores diferentes, comprende los problemas en cuestión :)

Ejemplo 1:

 const a = { n: 3 }; const b = { n: 5 }; function addNumbers(v1, v2) { const answer = { n: v1.n + v2.n }; return () => answer; } const c = addNumbers(a, b); an = 7; console.log('Eager Evaluation:', c());

Aquí, cn es igual a 3 + 5 porque c se evaluó antes de que an se estableciera en 7 . Esto es lo mismo que cuando recuperó al usuario antes de que se eliminara. Mientras tanto, no ve que la información del usuario haya cambiado porque el valor ya se calculó.

Ejemplo 2:

 const a = { n: 3 }; const b = { n: 5 }; function addNumbers(v1, v2) { return () => ({ n: v1.n + v2.n }); } const c = addNumbers(a, b); an = 7; console.log('Lazy Evaluation:', c());

Aquí, cn es igual a 7 + 5 porque c se evaluó después de que an se estableciera en 7 . Esto es lo mismo que cuando recuperó al usuario usando defer . Esta vez comprobamos el valor de an en el momento en que se evalúa c() , no cuando se evalúa addNumbers(v1, v2) .

¿Ver la diferencia?

over 4 years ago · Santiago Trujillo Relatório

0

Alguna explicación que me ayudó un par de veces a entender defer .

La composición de funciones se ejecuta de interior a exterior. Primero los argumentos internos dados a la función externa, luego la función externa.

 function f(x) { const result = x * 10; console.log("f: ", x, " -> ", result); return result; } function g(x) { const result = x + 1; console.log("g: ", x, " -> ", result); return result; } cosnole.log(f(g(2))) // g: 2 => 3 // f: 3 => 30 // 30

Las promesas están ansiosas. No esperan a que alguien se suscriba.

 new Promise(() => console.log("1")); console.log("2"); 1 2 function f(p) { console.log('f:'); } f(new Promise(() => console.log("1)); // 1 // f:

Así es el caso de from(somePromise) :

 from(new Promise((resolve) => { console.log("promise 1"); setTimeout(() => { console.log("promise 2"); resolve(5); }); }); console.log("subscribe - before"); from.pipe(tap(x) => { console.log("tap: ", x); }).subscribe(); console.log("subscribe - after"); // promise 1 // subscribe - before // subscribe - after // promise 2 // tap: 5

Qué hace detrás from escena (simplificado):

 function from(promise) { return new Observable(subscriber => { promise.then(result => { subscriber.next(result); subscriber.complete(); }, (err) => subscriber.error(err)); }); }

from devuelve un observable que emite cuando se emite la promesa, pero la promesa en sí ya comenzó a funcionar incluso antes de que from comenzara y creara un observable.

El operador defer es para esos casos. Cuando se desea retrasar el trabajo y solo ejecutarlo cuando alguien se suscribe.

Lo que defer hace detrás de escena (versión simplificada):

 function defer(workFunction) { return new Observable(subscriber => { from(workFunction()).subscribe((result) => { subscriber.next(result); }); }); }

Solo cuando alguien se suscribe, se activa la función de trabajo.

Si damos defer a switchMapTo , switchMapTo se suscribirá solo cuando su fuente emita.

Qué hace switchMapTo detrás de escena simplificado:

 function switchMapTo(workObservable) { let lastSubs; return new Observable(subscriber => { if (lastSubs) { lastSubs.unsubscribe(); } lastSubs = workObservable.pipe( tap(result => subscriber.next(result)), ).subscribe(); }); }
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda