Soy un poco nuevo en JS y me preguntaba si necesitaría hacer un objeto mutuamente excluyente si planeo escribir datos en él desde un montón de funciones asíncronas diferentes. Para dar un ejemplo más concreto, estoy tratando de analizar algunos datos relacionados con eventos deportivos de un montón de sitios web diferentes y quiero escribir información específica relacionada con dichos sitios en un objeto central que contiene información general sobre un evento deportivo y más. datos de eventos específicos que extraigo de cada sitio individual. Idealmente, todas estas operaciones serían asíncronas entre sí para mejorar el rendimiento.
¡Gracias por adelantado!
Nodejs ejecuta su Javascript en un solo hilo. Por lo tanto, dos partes de su Javascript no se ejecutarán activamente al mismo tiempo. Debido a esto, no tendrá problemas con dos partes de su Javascript que intentan acceder a un objeto al mismo tiempo exactamente como lo haría en algo así como un código C ++ de subprocesos múltiples. Esto es cierto sin importar cuál sea la fuente de su Javascript, ya sea que esté en una función async o no.
Incluso si usa WorkerThreads, no brindan acceso simultáneo a las mismas variables (cada WorkerThread tiene su propio espacio de variables) y comunicaría los cambios de valor a través de mensajes que se ejecutan a través del ciclo de eventos, coordinando así el acceso con su otro código. En el nivel más bajo de WorkerThreads, hay un tipo de datos SharedArrayBuffer que permite el acceso entre subprocesos y tendría que usar Atomics o algo similar para proteger su acceso. Pero, esta es una situación muy específica y solo un tipo de datos muy específico.
Dicho esto, todavía hay formas bastante simples de tener condiciones de carrera en Javascript y algunas de ellas involucran async/await Por ejemplo, si tiene algún recurso compartido al que está accediendo en su código (un recurso al que acceden otras partes de su código), luego, cada vez que presiona una devolución de llamada await o .then() en su código, ese es el lugar donde el intérprete regresa a la cola de promesas o al bucle de eventos y puede ejecutar otro código mientras espera que esa promesa se resuelva/rechace . Si ese otro código también puede modificar este recurso compartido y eso es un problema para el primer código, es posible que tenga una condición de carrera.
Entonces, si solo haces algo como esto:
let someValue = someSharedObj.prop; let delta = await someFunction(); someSharedObj.prop = someValue + delta; Debe saber que otro código puede acceder a someSharedObj mientras está en await y esto podría ser una condición de carrera en la que este código puede sobrescribir un cambio que hizo otro código mientras estaba sentado en await . Esto podría reescribirse como tal:
let delta = await someFunction(); let someValue = someSharedObj.prop; someSharedObj.prop = someValue + delta; Y la condición de carrera ya no existe porque es un código completamente síncrono entre el momento en que obtienes el accesorio, le agregas un valor y lo vuelves a escribir. Ningún otro Javascript puede ejecutarse entre esas dos últimas declaraciones. Si se ejecuta otro código durante la await , eso no causa ningún problema para actualizar someSharedObj .
Es un poco difícil aconsejar genéricamente sobre cómo evitarlos. Con una base de datos, la base de datos normalmente tendrá operaciones atómicas que puede usar para evitar condiciones de carrera, transacciones o bloqueos. Por ejemplo, la mayoría de las bases de datos tendrán una forma atómica de incrementar o disminuir un valor sin tener que obtener el valor de forma asíncrona, incrementarlo y escribirlo de nuevo de forma asíncrona (lo que es vulnerable a las condiciones de carrera).
Para sus propios datos compartidos, evitar las condiciones de carrera generalmente implica no retener datos a través de una devolución de llamada await o .then() .