Digamos que tengo esta función de autenticación que devuelve una promesa. La promesa luego se resuelve con el resultado. Falso y verdadero son los resultados esperados, según lo veo, y los rechazos solo deberían ocurrir en un caso de error. O, ¿una falla en la autenticación se considera algo por lo que rechazaría una promesa?
javascript
Mathieu Bertin
fuente
fuente
reject
y no devolver falso, pero si espera que el valor sea aBool
, entonces tuvo éxito y debe resolver con el Bool independientemente del valor. Las promesas son una especie de representación de los valores: almacenan el valor devuelto, por lo que solo si el valor no se puede obtener, usted debe hacerloreject
. De lo contrario deberíasresolve
.false
o una excepción?then
cuando el servidor responde, incluso si se devuelve un código de error, y debe verificar elresponse.ok
. Elcatch
controlador solo se activa para errores inesperados .Respuestas:
¡Buena pregunta! No hay una respuesta difícil. Depende de lo que considere excepcional en ese punto específico del flujo .
Rechazar a
Promise
es lo mismo que plantear una excepción. No todos los resultados no deseados son excepcionales , el resultado de errores . Podría argumentar su caso en ambos sentidos:Falló la autenticación debe
reject
alPromise
, debido a que la persona que llama está a la espera de unUser
objeto a cambio, y cualquier otra cosa es una excepción a este flujo.Falló la autenticación debe
resolve
alPromise
, aunque ennull
, ya que proporciona las credenciales incorrectas no es realmente un excepcional caso, y la persona que llama debe no espera que el flujo de siempre resulta en unUser
.Tenga en cuenta que estoy mirando el problema desde el lado de la persona que llama . En el flujo de información, ¿la persona que llama espera que sus acciones resulten en un
User
(y cualquier otra cosa es un error), o tiene sentido que esta persona en particular maneje otros resultados?En un sistema de varias capas, la respuesta puede cambiar a medida que los datos fluyen a través de las capas. Por ejemplo:
null
usuario.Este ejemplo de 4 puntos es obviamente complicado, pero ilustra 2 puntos:
Así que de nuevo, no hay respuesta difícil. ¡Hora de pensar y diseñar!
fuente
Por lo tanto, las promesas tienen una buena propiedad que aportan JS de lenguajes funcionales, que es que implementan este
Either
constructor de tipos que une dos otros tipos, elLeft
tipo y elRight
tipo, al forzar a la lógica a tomar una rama u otra rama.Ahora se está dando cuenta de que el tipo en el lado izquierdo es ambiguo para las promesas; puedes rechazar con cualquier cosa. Esto es cierto porque JS está tipado débilmente, pero debes ser cauteloso si estás programando a la defensiva.
La razón es que JS tomará
throw
declaraciones del código de manejo de promesas y lo agrupará en elLeft
lado de eso también. Técnicamente en JS puedesthrow
todo, incluso verdadero / falso o una cadena o un número: pero el código JavaScript también arroja cosas sinthrow
(cuando haces cosas como intentar acceder a propiedades en nulos) y hay una API establecida para esto (elError
objeto) . Entonces, cuando empiezas a atrapar, generalmente es bueno poder asumir que esos errores sonError
objetos. Y dadoreject
que la promesa se aglomerará en cualquier error de cualquiera de los errores anteriores, generalmente solo deseathrow
otros errores, para que sucatch
declaración tenga una lógica simple y consistente.Por lo tanto, aunque puede poner un if-conditional en su
catch
y buscar errores falsos, en cuyo caso el caso de la verdad es trivial,probablemente preferirá la estructura lógica, al menos para lo que sale inmediatamente del autenticador, de un booleano más simple:
De hecho, el siguiente nivel de lógica de autenticación es probablemente devolver algún tipo de
User
objeto que contenga al usuario autenticado, de modo que esto se convierta en:y esto es más o menos lo que esperaría: regresar
null
en el caso de que el usuario no esté definido; de lo contrario, regresar{user_id: <number>, permission_to_launch_missiles: <boolean>}
. Esperaría que el caso general de no iniciar sesión sea rescatable, por ejemplo, si estamos en algún tipo de modo "demostración a nuevos clientes", y no debería mezclarse con errores donde accidentalmente llaméobject.doStuff()
cuandoobject.doStuff
estabaundefined
.Ahora con eso dicho, lo que es posible que desee hacer es definir una
NotLoggedIn
oPermissionError
excepción que se deriva deError
. Luego, en las cosas que realmente lo necesitan, desea escribir:fuente
Errores
Hablemos de errores.
Hay dos tipos de errores:
Errores esperados
Los errores esperados son estados en los que sucede algo incorrecto, pero usted sabe que podría ocurrir, por lo que debe lidiar con eso.
Estas son cosas como la entrada del usuario o solicitudes del servidor. Usted sabe que el usuario puede cometer un error o que el servidor puede estar inactivo, por lo que debe escribir un código de verificación para asegurarse de que el programa solicite información nuevamente, o muestre un mensaje, o cualquier otro comportamiento apropiado.
Estos son recuperables cuando se manejan. Si se deja sin control, se convierten en errores inesperados.
Errores inesperados
Los errores inesperados (errores) son estados en los que sucede algo incorrecto porque el código es incorrecto. Sabes que eventualmente sucederán, pero no hay forma de saber dónde o cómo lidiar con ellos porque, por definición, son inesperados.
Estas son cosas como la sintaxis y los errores lógicos. Puede tener un error tipográfico en su código, puede haber llamado a una función con los parámetros incorrectos. Estos no suelen ser recuperables.
try..catch
Hablemos de eso
try..catch
.En JavaScript,
throw
no se usa comúnmente. Si busca ejemplos en el código, serán pocos y distantes entre sí, y generalmente estructurados de acuerdo con las líneas deDebido a esto, los
try..catch
bloques tampoco son tan comunes para el flujo de control. Por lo general, es bastante fácil agregar algunas comprobaciones antes de llamar a los métodos para evitar los errores esperados.Los entornos JavaScript también son bastante indulgentes, por lo que los errores inesperados a menudo también se dejan sin detectar.
C # :try..catch
no tiene que ser infrecuente Hay algunos casos de uso agradables, que son más comunes en lenguajes como Java y C #. Java y C # tienen la ventaja de lascatch
construcciones escritas , para que pueda diferenciar entre errores esperados e inesperados:Este ejemplo permite que otras excepciones inesperadas fluyan y se manejen en otro lugar (como iniciar sesión y cerrar el programa).
En JavaScript, esta construcción se puede replicar a través de:
No es tan elegante, que es parte de la razón por la cual es poco común.
Las funciones
Hablemos de funciones.
Si utiliza el principio de responsabilidad única , cada clase y función debe cumplir un propósito singular.
Por ejemplo,
authenticate()
podría autenticar a un usuario.Esto podría escribirse como:
Alternativamente, podría escribirse como:
Ambos son aceptables.
Promesas
Hablemos de promesas.
Las promesas son una forma asincrónica de
try..catch
. Llamandonew Promise
oPromise.resolve
comienza sutry
código. Llamandothrow
oPromise.reject
te envía alcatch
código.Si tiene una función asincrónica para autenticar a un usuario, puede escribirla como:
Alternativamente, podría escribirse como:
Ambos son aceptables.
Anidamiento
Hablemos de anidar.
try..catch
puede ser anidado Suauthenticate()
método puede tener internamente untry..catch
bloque como:Del mismo modo, las promesas se pueden anidar. Su
authenticate()
método asíncrono podría usar promesas internamente:Entonces, ¿cuál es la respuesta?
Ok, creo que es hora de que realmente responda la pregunta:
La respuesta más simple que puedo dar es que debe rechazar una promesa en cualquier lugar donde de lo contrario desearía
throw
una excepción si fuera un código síncrono.Si su flujo de control es más simple al hacer algunas
if
verificaciones en susthen
declaraciones, no hay necesidad de rechazar una promesa.Si su flujo de control es más simple al rechazar una promesa y luego verificar los tipos de errores en su código de manejo de errores, hágalo en su lugar.
fuente
He usado la rama "rechazar" de una Promesa para representar la acción "cancelar" de los cuadros de diálogo de jQuery UI. Parecía más natural que usar la rama "resolver", sobre todo porque a menudo hay múltiples opciones de "cerrar" en un cuadro de diálogo.
fuente
Manejar una promesa es más o menos como una condición de "si". Depende de usted si desea "resolver" o "rechazar" si la autenticación falla.
fuente
try..catch
, noif
.try...catch
y simplemente decir que si pudo completar y obtener un resultado, debe resolver independientemente del valor recibido, de lo contrario, ¿debe rechazar?try { if (!doSomething()) throw whatever; doSomethingElse() } catch { ... }
está perfectamente bien, pero la construcción quePromise
representa a es latry..catch
parte, no laif
parte.doSomething()
falla, arrojará, pero si no podría contener el valor que necesita (loif
anterior es un poco confuso ya que no es parte de su idea aquí :)). Solo debe rechazar si hay una razón para lanzar (en la analogía), por lo tanto, si la prueba falló. Si la prueba tuvo éxito, siempre debe resolver, independientemente de si su valor es positivo, ¿verdad?