Red de conocimiento informático - Material del sitio web - Detalles de cómo escribir a mano la biblioteca Promise desde cero usando js

Detalles de cómo escribir a mano la biblioteca Promise desde cero usando js

Prefacio

ECMAScript es el estándar internacional para el lenguaje JavaScript y JavaScript es la implementación de ECMAScript.

El objetivo de ES6 es hacer que el lenguaje JavaScript sea utilizable para escribir aplicaciones grandes y complejas y convertirlo en un lenguaje de desarrollo de nivel empresarial.

Concepto

ES6 proporciona objetos Promise de forma nativa.

Promise es un objeto que entrega mensajes para operaciones asincrónicas. Representa un evento (normalmente una operación asincrónica) cuyo resultado se conocerá en el futuro y proporciona una API unificada para su posterior procesamiento.

Tres pensamientos

Cuando comencé a escribir interfaces, a menudo usaba devoluciones de llamada para manejar solicitudes asincrónicas. Después de eso, dejé las devoluciones de llamada y comencé a usar promesas para abordar problemas asincrónicos. Promise es realmente hermoso de escribir, pero debido a la falta de una comprensión profunda de su estructura interna, cada vez que se encuentra con situaciones complejas, Promesa no siempre es fácil de usar y lleva mucho tiempo depurarla.

Entonces, en este artículo, lo llevaré desde cero a escribir a mano una promesa básica y utilizable. Cuando siga mis ideas, comprenderá claramente qué es una promesa y cuál es su estructura interna. Puedes utilizar promesas en escenarios complejos en el futuro.

Finalmente, para comprobar tu comprensión del compromiso, finalizaré este artículo con algunos ejercicios relacionados con el compromiso. Estos problemas son abstracciones de escenarios reales que encontrará en sus proyectos, y dominarlos le ayudará a utilizar mejor la interfaz.

Estos tres ejercicios se proporcionan con antelación, por lo que puedes saltarte lo siguiente y pensar en cómo resolverlos:

¿Llamadas encadenadas a una matriz de promesa?

¿Cómo controla la promesa la concurrencia?

¿Cómo almacenar en caché las promesas de forma asincrónica?

Estos tres problemas tienen poco que ver con si usa o no promesas, pero si no tiene un conocimiento profundo de las promesas, no es fácil resolver estos tres problemas.

¿Qué es un compromiso?

Volviendo al tema, ¿qué es un compromiso? En pocas palabras, una promesa es un contenedor que contiene los resultados de un evento (normalmente una operación asincrónica) que finalizará en el futuro.

En primer lugar, ES6 estipula que el objeto Promise es un constructor utilizado para generar instancias de Promise. Finalmente, después de generar una instancia de Promise, puede usar el método then para especificar funciones de devolución de llamada para los estados resuelto y rechazado (onFulfilled y onRejected) respectivamente. entonces( función(valor) {

// éxito

}, función(error) {

// fracaso

}) ;

Entendiendo esto, podemos comenzar audazmente a construir nuestras propias promesas. Nombre: CutePromise

Implementar una promesa: CutePromise

Crearemos nuestra CutePromise directamente desde la clase ES6. Si no está familiarizado con la sintaxis de ES6, puede leer mis otros dos artículos de introducción. Artículo de gramática central de ES6 y luego regrese. Núcleo de ES6/ES2015 (Parte 1), maestro del núcleo de ES6/ES2015 en 30 minutos (Parte 2)

class CutePromise {

// ejecutor es la función de parámetro que pasamos al crear instancias CutePromise, que acepta dos parámetros: resolver y rechazar.

// resolver y rechazar se definirán en el constructor para que el ejecutor llame durante la ejecución

constructor(ejecutor) {

const resolve = () = > {}

const rechazar = () =>{}

ejecutor(resolver, rechazar)

}

/ / Proporcione un método then para la instancia, que recibe una función de dos parámetros

// La función del primer parámetro es obligatoria y se llamará después de que la promesa se cumpla por completo

// El El segundo parámetro es opcional, se llamará después de que la promesa falle (rechazada)

luego (onFulfilled, onRejected) {}

}

Creando CutePromise Después de crear CutePromise, descubramos otro punto clave: el estado del objeto Promise.

Los objetos de promesa controlan las operaciones asincrónicas a través de su estado. Una instancia de Promise tiene tres estados:

Operación asincrónica pendiente

Operación asincrónica ejecutada con éxito

Operación asincrónica rechazada

Entre los tres anteriores estados, los estados ejecutado y rechazado se denominan colectivamente estado resuelto. Solo hay dos caminos para cambiar de estado: uno comienza desde pendiente=>cumplido, el otro comienza desde pendiente=>rechazado, y una vez que se cambia el estado, no se puede cambiar.

Ahora agreguemos un estado a CutePromise. El proceso general es:

Primero, durante el proceso inicial de creación de instancias, configuramos el estado en PENDIENTE, y luego cuando el ejecutor se ejecuta. resolve, el estado cambiará a CUMPLIDO y cuando el ejecutor ejecute REJECT, el estado cambiará a REJECT.

constructor(ejecutor) {

...

this.state = 'PENDIENTE';

...

const resolve = (resultado) => {

this.state = 'CUMPLIDO';

this.value = resultado;

}

const rechazar = (error) => {

this.state = 'RECHAZADO';

this.value = error;

}

...

}

Eche un vistazo a nuestra función then. La función then recibe dos parámetros: onFulfilled (promesa que el la operación asincrónica es exitosa La función llamada cuando falla la operación asincrónica prometida) y onRejected (la función llamada cuando falla la operación asincrónica prometida). Si la promesa se ha completado cuando llamamos a la función (cuando la tarea es una tarea sincrónica), podemos ejecutar la función directamente según el estado de la instancia. Si el estado de la promesa aún es PENDIENTE, almacenamos onFulfilled y onRejected directamente en las variables encadenadas y esperamos a que se complete la promesa antes de llamarla.

constructor(executor) {

...value = result;

// La promesa se ha ejecutado exitosamente y puedes llamar a .then() función en secuencia función onFulfilled

for (const { onFulfilled } of this.chained) {

onFulfilled(res);

}

}

...

}

entonces(onFulfilled, onRejected) {

if (this.state === ' CUMPLIDO') {

onFulfilled(this.value);

} else if (this .state === 'REJECTED') {

onRejected(this .value) ;

} else {

this.$chained.push({ onFulfilled, onRejected });

}

}

Esto completa la creación de CutePromise. El siguiente es el código completo, puedes probarlo en la consola:

class CutePromise {

constructor(executor). ) {

p>

if (typeof executor !== 'función') {

throw new Error('El ejecutor debe ser una función');

}

this.state = 'PENDIENTE';

this.chained = [];

const resolve = res => {

if (this.state ! == 'PENDING') {

return;

}

this.state = 'CUMPLIDO';

this.internalValue = res;

for (const { onFulfilled } de este .chained) {

onFulfilled(res);

}

} ;

const rechazar = err => {

if (this.state ! == 'PENDIENTE') {

return;

}

this.state = 'RECHAZADO';

this.internalValue = err;

for (const { onRejected } de this.chained) {

onRejected(err);

}

};

prueba {

ejecutor(resolver, rechazar) ;

} catch (err) {

rechazar(err);

}

}

} .chained.push({ onFulfilled, onRejected });

}

}

Proporcione un código de prueba: <

/p>

let p = new CutePromise(resolve => {

setTimeout(() => resolve(' Hola'), 100);

});

p.then(res => console.log(res));

p = new CutePromise((resolver, rechazar) => {

setTimeout( () => rechazar(nuevo Error));

p = new CutePromise((resolver, rechazar) => {

setTimeout(() => rechazar(nuevo Error(' woops')), 100);

});

p.then(() => {}, err => console.log('Error asíncrono:', err .stack));

p = new CutePromise(() => { throw new Error('woops'); });

p.then(() => { }, err => console.log('Error de sincronización:', err.stack));

Resumen