Buscar..


Sintaxis

  • nueva Promesa (/ * función ejecutora: * / función (resolver, rechazar) {})
  • promesa.then (onFulfilled [, onRejected])
  • promise.catch (onRejected)
  • Promise.resolve (resolución)
  • Promise.reject (razón)
  • Promise.all (iterable)
  • Promesa.race (iterable)

Observaciones

Las promesas forman parte de la especificación ECMAScript 2015 y el soporte del navegador es limitado, ya que el 88% de los navegadores en todo el mundo lo admiten a partir de julio de 2017. La siguiente tabla ofrece una descripción general de las versiones más antiguas del navegador que brindan soporte para las promesas.

Cromo Borde Firefox explorador de Internet Ópera mini Opera Safari iOS Safari
32 12 27 X 19 X 7.1 8

En entornos que no los admiten, Promise se puede rellenar con polietileno. Las bibliotecas de terceros también pueden proporcionar funcionalidades extendidas, como la "promisificación" automatizada de las funciones de devolución de llamada o métodos adicionales como el progress también conocido como notify .

El sitio web Promises / A + standard proporciona una lista de implementaciones compatibles con 1.0 y 1.1 . Las devoluciones de llamada de promesa basadas en el estándar A + siempre se ejecutan de forma asincrónica como microtasks en el bucle de eventos .

Encadenamiento de promesa

La then método de una promesa devuelve una nueva promesa.

const promise = new Promise(resolve => setTimeout(resolve, 5000));

promise
    // 5 seconds later
    .then(() => 2)
    // returning a value from a then callback will cause
    // the new promise to resolve with this value
    .then(value => { /* value === 2 */ });

Devolver una Promise de una devolución de llamada en then agregará a la cadena de promesa.

function wait(millis) {
    return new Promise(resolve => setTimeout(resolve, millis));
}

const p = wait(5000).then(() => wait(4000)).then(() => wait(1000));
p.then(() => { /* 10 seconds have passed */ });

Una catch permite que una promesa rechazada se recupere, de manera similar a cómo funciona la catch en una declaración de try / catch . Cualquier encadenado then una catch ejecutará su controlador de resolución utilizando el valor resuelto de la catch .

const p = new Promise(resolve => {throw 'oh no'});
p.catch(() => 'oh yes').then(console.log.bind(console));  // outputs "oh yes"

Si no hay catch o reject en el medio de la cadena, una catch al final capturará cualquier rechazo en la cadena:

p.catch(() => Promise.reject('oh yes'))
  .then(console.log.bind(console))      // won't be called
  .catch(console.error.bind(console));  // outputs "oh yes"

En ciertas ocasiones, es posible que desee "ramificar" la ejecución de las funciones. Puede hacerlo devolviendo diferentes promesas desde una función dependiendo de la condición. Más adelante en el código, puede combinar todas estas ramas en una para llamar a otras funciones y / o para manejar todos los errores en un solo lugar.

promise
    .then(result => {          
        if (result.condition) {
            return handlerFn1() 
                .then(handlerFn2);
        } else if (result.condition2) {
            return handlerFn3()
                .then(handlerFn4);
        } else {
            throw new Error("Invalid result");
        }
    })
    .then(handlerFn5)
    .catch(err => {
        console.error(err);
    });

Así, el orden de ejecución de las funciones se ve así:

promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
         |                            ^
         V                            |
         -> handlerFn3 -> handlerFn4 -^            

La catch única obtendrá el error en cualquier rama que pueda ocurrir.

Introducción

Un objeto Promise representa una operación que ha producido o que eventualmente producirá un valor. Las promesas proporcionan una forma sólida de envolver el resultado (posiblemente pendiente) de un trabajo asíncrono, mitigando el problema de las devoluciones de llamadas profundamente anidadas (conocidas como " infierno de devolución de llamada ").

Estados y flujo de control.

Una promesa puede estar en uno de tres estados:

  • pendiente : la operación subyacente aún no se ha completado, y la promesa está pendiente de cumplimiento.
  • cumplido : la operación ha finalizado y la promesa se cumple con un valor . Esto es análogo a devolver un valor desde una función síncrona.
  • rechazado : se ha producido un error durante la operación y la promesa se rechaza con un motivo . Esto es análogo a lanzar un error en una función síncrona.

Se dice que una promesa se liquida (o se resuelve ) cuando se cumple o se rechaza. Una vez que se establece una promesa, se vuelve inmutable y su estado no puede cambiar. Los métodos then y catch de una promesa se pueden usar para adjuntar devoluciones de llamada que se ejecutan cuando se resuelve. Estas devoluciones de llamada se invocan con el valor de cumplimiento y el motivo de rechazo, respectivamente.

Diagrama de flujo de promesa

Ejemplo

const promise = new Promise((resolve, reject) => {
    // Perform some work (possibly asynchronous)
    // ...

    if (/* Work has successfully finished and produced "value" */) {
        resolve(value);
    } else {
        // Something went wrong because of "reason"
        // The reason is traditionally an Error object, although
        // this is not required or enforced.
        let reason = new Error(message);
        reject(reason);

        // Throwing an error also rejects the promise.
        throw reason;
    }
});

Los métodos then y catch se pueden usar para adjuntar devoluciones de llamadas de cumplimiento y rechazo:

promise.then(value => {
    // Work has completed successfully,
    // promise has been fulfilled with "value"
}).catch(reason => {
    // Something went wrong,
    // promise has been rejected with "reason"
});

Nota: Llamar a promise.then(...) y promise.catch(...) en la misma promesa puede dar como resultado una Uncaught exception in Promise si se produce un error, ya sea al ejecutar la promesa o dentro de una de las devoluciones de llamada, por lo que la forma preferida sería adjuntar la siguiente oyente con la promesa de regresar por el anterior then / catch .

Alternativamente, ambas devoluciones de llamada se pueden adjuntar en una sola llamada para then :

promise.then(onFulfilled, onRejected);

Adjuntar devoluciones de llamada a una promesa que ya se ha resuelto las colocará inmediatamente en la cola de microtask , y se invocarán "tan pronto como sea posible" (es decir, inmediatamente después de la secuencia de comandos en ejecución). No es necesario verificar el estado de la promesa antes de adjuntar devoluciones de llamada, a diferencia de muchas otras implementaciones que emiten eventos.


Demo en vivo

Función de retardo llamada

El método setTimeout() llama a una función o evalúa una expresión después de un número específico de milisegundos. También es una forma trivial de lograr una operación asíncrona.

En este ejemplo, llamar a la función de wait resuelve la promesa después del tiempo especificado como primer argumento:

function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));  
}

wait(5000).then(() => { 
    console.log('5 seconds have passed...');
});

Esperando múltiples promesas concurrentes

El método estático Promise.all() acepta una promesa (por ejemplo, una Array ) de promesas y devuelve una nueva promesa, que se resuelve cuando todas las promesas en la iterable se han resuelto, o se rechazan si al menos una de las promesas en la iterable se ha rechazado.

// wait "millis" ms, then resolve with "value"
function resolve(value, milliseconds) {
    return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}

// wait "millis" ms, then reject with "reason"
function reject(reason, milliseconds) {
    return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    resolve(3, 7000)    
]).then(values => console.log(values)); // outputs "[1, 2, 3]" after 7 seconds.

Promise.all([
    resolve(1, 5000),
    reject('Error!', 6000),
    resolve(2, 7000)
]).then(values => console.log(values)) // does not output anything
.catch(reason => console.log(reason)); // outputs "Error!" after 6 seconds.

Los valores no prometedores en lo iterable son "promisificados" .

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    { hello: 3 }
])
.then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds

La tarea de destrucción puede ayudar a recuperar resultados de múltiples promesas.

Promise.all([
    resolve(1, 5000),
    resolve(2, 6000),
    resolve(3, 7000)
])
.then(([result1, result2, result3]) => {
    console.log(result1);
    console.log(result2);
    console.log(result3);
});

Esperando la primera de las múltiples promesas concurrentes.

El método estático Promise.race() acepta una Promesa iterable y devuelve una Promesa nueva que se resuelve o rechaza tan pronto como la primera de las promesas en el iterable se resuelve o rechaza.

// wait "milliseconds" milliseconds, then resolve with "value"
function resolve(value, milliseconds) {
    return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}

// wait "milliseconds" milliseconds, then reject with "reason"
function reject(reason, milliseconds) {
    return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}

Promise.race([
    resolve(1, 5000),
    resolve(2, 3000),
    resolve(3, 1000)
])
.then(value => console.log(value)); // outputs "3" after 1 second.


Promise.race([
    reject(new Error('bad things!'), 1000),
    resolve(2, 2000)
])
.then(value => console.log(value)) // does not output anything
.catch(error => console.log(error.message)); // outputs "bad things!" after 1 second

Valores "prometedores"

El método estático Promise.resolve se puede usar para envolver valores en promesas.

let resolved = Promise.resolve(2);
resolved.then(value => {
    // immediately invoked
    // value === 2
});

Si el value ya es una promesa, Promise.resolve simplemente la Promise.resolve .

let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
let two = Promise.resolve(one);
two.then(value => {
    // 1 second has passed
    // value === 2
});

De hecho, value puede ser cualquier "thenable" (objeto que define una then método que funciona suficientemente como una promesa spec compatible). Esto permite que Promise.resolve convierta los objetos de terceros no confiables en Promesas de terceros confiables.

let resolved = Promise.resolve({
    then(onResolved) {
        onResolved(2);
    }
});
resolved.then(value => {
    // immediately invoked
    // value === 2
});

El método estático Promise.reject devuelve una promesa que se rechaza inmediatamente con el reason dado.

let rejected = Promise.reject("Oops!");
rejected.catch(reason => {
    // immediately invoked
    // reason === "Oops!"
});

Funciones "prometedoras" con devoluciones de llamada

Dada una función que acepta una devolución de llamada de estilo de nodo,

fooFn(options, function callback(err, result) { ... });

puedes promisificarlo (convertirlo en una función basada en la promesa) de esta manera:

function promiseFooFn(options) {
    return new Promise((resolve, reject) =>
        fooFn(options, (err, result) =>
            // If there's an error, reject; otherwise resolve
            err ? reject(err) : resolve(result)
        )
    );
}

Esta función se puede utilizar de la siguiente manera:

promiseFooFn(options).then(result => {
    // success!
}).catch(err => {
    // error!
});

De una manera más genérica, aquí se muestra cómo prometer cualquier función dada de estilo de devolución de llamada:

function promisify(func) {
    return function(...args) {
        return new Promise((resolve, reject) => {
            func(...args, (err, result) => err ? reject(err) : resolve(result));
        });
    }
}

Esto se puede utilizar de esta manera:

const fs = require('fs');
const promisedStat = promisify(fs.stat.bind(fs));

promisedStat('/foo/bar')
    .then(stat => console.log('STATE', stat))
    .catch(err => console.log('ERROR', err));

Manejo de errores

Los errores generados por las promesas se manejan mediante el segundo parámetro ( reject ) que se pasa a then o por el controlador que se pasa a catch :

throwErrorAsync()
  .then(null, error => { /* handle error here */ });
// or
throwErrorAsync()
  .catch(error => { /* handle error here */ });

Encadenamiento

Si tiene una cadena de promesa, un error hará que se resolve manejadores de resolve :

throwErrorAsync()
  .then(() => { /* never called */ })
  .catch(error => { /* handle error here */ });

Lo mismo se aplica a sus funciones de then . Si un controlador de resolve lanza una excepción, se invocará el siguiente controlador de reject :

doSomethingAsync()
  .then(result => { throwErrorSync(); })
  .then(() => { /* never called */ })
  .catch(error => { /* handle error from throwErrorSync() */ });

Un controlador de errores devuelve una nueva promesa, permitiéndole continuar una cadena de promesa. La promesa devuelta por el controlador de errores se resuelve con el valor devuelto por el controlador:

throwErrorAsync()
  .catch(error => { /* handle error here */; return result; })
  .then(result => { /* handle result here */ });

Puedes dejar que un error caiga en cascada en una cadena de promesa volviendo a lanzar el error:

throwErrorAsync()
  .catch(error => {
      /* handle error from throwErrorAsync() */
      throw error;
  })
  .then(() => { /* will not be called if there's an error */ })
  .catch(error => { /* will get called with the same error */ });

Es posible lanzar una excepción que no esté manejada por la promesa envolviendo la declaración de throw dentro de una setTimeout llamada setTimeout :

new Promise((resolve, reject) => {
  setTimeout(() => { throw new Error(); });
});

Esto funciona porque las promesas no pueden manejar las excepciones lanzadas de forma asíncrona.

Rechazos no manejados

Un error se ignorará silenciosamente si una promesa no tiene un bloque catch o un controlador de reject :

throwErrorAsync()
  .then(() => { /* will not be called */ });
// error silently ignored

Para evitar esto, siempre use un bloque catch :

throwErrorAsync()
  .then(() => { /* will not be called */ })
  .catch(error => { /* handle error*/ });
// or
throwErrorAsync()
  .then(() => { /* will not be called */ }, error => { /* handle error*/ });

Alternativamente, suscríbase al evento unhandledrejection para capturar cualquier promesa rechazada no manejada:

window.addEventListener('unhandledrejection', event => {});

Algunas promesas pueden manejar su rechazo más tarde que su tiempo de creación. El evento manejado por el rejectionhandled se desencadena cuando se maneja tal promesa:

window.addEventListener('unhandledrejection', event => console.log('unhandled'));
window.addEventListener('rejectionhandled', event => console.log('handled'));
var p = Promise.reject('test');

setTimeout(() => p.catch(console.log), 1000);

// Will print 'unhandled', and after one second 'test' and 'handled'

El argumento del event contiene información sobre el rechazo. event.reason es el objeto de error y event.promise es el objeto de promesa que causó el evento.

En nodejs los rejectionhandled y unhandledrejection eventos se llaman rejectionHandled y unhandledRejection el process , respectivamente, y tienen una firma diferente:

process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});

El argumento de la reason es el objeto de error y el argumento de promise es una referencia al objeto de promesa que causó que el evento se activara.

El uso de estos eventos de rejectionhandled y rejectionhandled unhandledrejection debe considerarse solo para fines de depuración. Típicamente, todas las promesas deben manejar sus rechazos.

Nota: Actualmente, solo Chrome 49+ y Node.js son compatibles con los eventos de rejectionhandled y rejectionhandled unhandledrejection manejados.

Advertencias

Encadenamiento con fulfill y reject

La función then(fulfill, reject) (con ambos parámetros no null ) tiene un comportamiento único y complejo, y no debe usarse a menos que sepa exactamente cómo funciona.

La función funciona como se espera si se otorga un null para una de las entradas:

// the following calls are equivalent
promise.then(fulfill, null) 
promise.then(fulfill)

// the following calls are also equivalent
promise.then(null, reject) 
promise.catch(reject)

Sin embargo, adopta un comportamiento único cuando se dan ambas entradas:

// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.then(fulfill).catch(reject)

// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.catch(reject).then(fulfill)

La función then(fulfill, reject) parece que es un atajo para then(fulfill).catch(reject) , pero no lo es, y causará problemas si se usa indistintamente. Uno de estos problemas es que el controlador de reject no controla los errores del controlador de fulfill . Esto es lo que sucederá:

Promise.resolve() // previous promise is fulfilled
    .then(() => { throw new Error(); }, // error in the fulfill handler
        error => { /* this is not called! */ });

El código anterior dará lugar a una promesa rechazada porque el error se propaga. Compárelo con el siguiente código, que resulta en una promesa cumplida:

Promise.resolve() // previous promise is fulfilled
    .then(() => { throw new Error(); }) // error in the fulfill handler
    .catch(error => { /* handle error */ });

Existe un problema similar cuando se usa then(fulfill, reject) indistintamente con catch(reject).then(fulfill) , excepto con promesas cumplidas en lugar de promesas rechazadas.

Lanzamiento sincrónico de la función que debería devolver una promesa.

Imagina una función como esta:

function foo(arg) {
  if (arg === 'unexepectedValue') {
    throw new Error('UnexpectedValue')
  }

  return new Promise(resolve => 
    setTimeout(() => resolve(arg), 1000)
  )
}

Si dicha función se usa en medio de una cadena de promesa, entonces aparentemente no hay problema:

makeSomethingAsync().
  .then(() => foo('unexpectedValue'))
  .catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here

Sin embargo, si la misma función se llama fuera de una cadena de promesa, entonces el error no será manejado por ella y se lanzará a la aplicación:

foo('unexpectedValue') // <-- error will be thrown, so the application will crash
  .then(makeSomethingAsync) // <-- will not run
  .catch(err => console.log(err)) // <-- will not catch

Hay 2 soluciones posibles:

Devuelve una promesa rechazada con el error.

En lugar de lanzar, haz lo siguiente:

function foo(arg) {
  if (arg === 'unexepectedValue') {
    return Promise.reject(new Error('UnexpectedValue'))
  }

  return new Promise(resolve => 
    setTimeout(() => resolve(arg), 1000)
  )
}

Envuelve tu función en una cadena de promesa

Su declaración de throw se capturará correctamente cuando ya esté dentro de una cadena de promesa:

function foo(arg) {
  return Promise.resolve()
    .then(() => {
      if (arg === 'unexepectedValue') {
        throw new Error('UnexpectedValue')
      }

      return new Promise(resolve => 
        setTimeout(() => resolve(arg), 1000)
      )
    })
}

Conciliación de operaciones síncronas y asíncronas.

En algunos casos, es posible que desee ajustar una operación síncrona dentro de una promesa para evitar la repetición en las ramas de código. Tomemos este ejemplo:

if (result) { // if we already have a result
  processResult(result); // process it
} else {
  fetchResult().then(processResult);
}

Las ramas síncronas y asíncronas del código anterior se pueden reconciliar envolviendo de forma redundante la operación síncrona dentro de una promesa:

var fetch = result
  ? Promise.resolve(result)
  : fetchResult();

fetch.then(processResult);

Cuando se almacena en caché el resultado de una llamada asíncrona, es preferible almacenar la promesa en lugar del resultado en sí. Esto garantiza que solo se requiere una operación asíncrona para resolver múltiples solicitudes paralelas.

Se debe tener cuidado de invalidar los valores almacenados en caché cuando se encuentran condiciones de error.

// A resource that is not expected to change frequently
var planets = 'http://swapi.co/api/planets/';
// The cached promise, or null
var cachedPromise;

function fetchResult() {
    if (!cachedPromise) {
        cachedPromise = fetch(planets)
            .catch(function (e) {
                // Invalidate the current result to retry on the next fetch
                cachedPromise = null;
                // re-raise the error to propagate it to callers
                throw e;
            });
    }
    return cachedPromise;
}

Reducir una matriz a promesas encadenadas

Este patrón de diseño es útil para generar una secuencia de acciones asíncronas a partir de una lista de elementos.

Hay dos variantes:

  • la reducción "entonces", que construye una cadena que continúa mientras la cadena experimente el éxito.
  • la reducción de "captura", que construye una cadena que continúa mientras la cadena experimenta un error.

La reducción "entonces"

Esta variante del patrón crea una cadena .then() , y puede usarse para encadenar animaciones, o hacer una secuencia de solicitudes HTTP dependientes.

[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.then(() => {
        console.log(n);
        return new Promise(res => setTimeout(res, 1000));
    });
}, Promise.resolve()).then(
    () => console.log('done'),
    (e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals

Explicación:

  1. Llamamos a .reduce() en una matriz de origen y proporcionamos Promise.resolve() como un valor inicial.
  2. Cada elemento reducido agregará un .then() al valor inicial.
  3. reduce() será Promise.resolve (). then (...). then (...).
  4. .then(successHandler, errorHandler) manualmente un .then(successHandler, errorHandler) después de la reducción, para ejecutar successHandler una vez que se hayan resuelto todos los pasos anteriores. Si algún paso fallara, se ejecutaría errorHandler .

Nota: La reducción "entonces" es una contraparte secuencial de Promise.all() .

La reducción de "captura"

Esta variante del patrón crea una cadena .catch() y puede usarse para sondear secuencialmente un conjunto de servidores web para algún recurso duplicado hasta que se encuentre un servidor que funcione.

var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
    return seq.catch(() => {
        console.log(n);
        if(n === working_resource) { // 5 is working
            return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
        } else { // all other values are not working
            return new Promise((resolve, reject) => setTimeout(reject, 1000));
        }
    });
}, Promise.reject()).then(
    (n) => console.log('success at: ' + n),
    () => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals

Explicación:

  1. Llamamos a .reduce() en una matriz de origen y proporcionamos Promise.reject() como un valor inicial.
  2. Cada elemento reducido agregará un .catch() al valor inicial.
  3. reduce() será Promise.reject().catch(...).catch(...) .
  4. .then(successHandler, errorHandler) manualmente .then(successHandler, errorHandler) después de la reducción, para ejecutar successHandler una vez que se haya resuelto alguno de los pasos anteriores. Si todos los pasos fuesen errorHandler , entonces se ejecutaría errorHandler .

Nota: La reducción de "captura" es una contrapartida secuencial de Promise.any() (como se implementó en bluebird.js , pero actualmente no está en ECMAScript nativo).

para cada uno con promesas

Es posible aplicar efectivamente una función ( cb ) que devuelve una promesa a cada elemento de una matriz, con cada elemento en espera de ser procesado hasta que se procese el elemento anterior.

function promiseForEach(arr, cb) {
  var i = 0;

  var nextPromise = function () {
    if (i >= arr.length) {
      // Processing finished.
      return;
    }

    // Process next function. Wrap in `Promise.resolve` in case
    // the function does not return a promise
    var newPromise = Promise.resolve(cb(arr[i], i));
    i++;
    // Chain to finish processing.
    return newPromise.then(nextPromise);
  };

  // Kick off the chain.
  return Promise.resolve().then(nextPromise);
};

Esto puede ser útil si necesita procesar eficientemente miles de artículos, uno a la vez. El uso de un bucle for regular for crear las promesas los creará todos a la vez y ocupará una cantidad significativa de RAM.

Realizando la limpieza con finalmente ()

Actualmente hay una propuesta (que aún no forma parte del estándar ECMAScript) para agregar una devolución de llamada finally a las promesas que se ejecutarán independientemente de si la promesa se cumple o se rechaza. Semánticamente, esto es similar a la cláusula finally del bloque try .

Usualmente usaría esta funcionalidad para la limpieza:

var loadingData = true;

fetch('/data')
    .then(result => processData(result.data))
    .catch(error => console.error(error))
    .finally(() => {
        loadingData = false;
    });

Es importante tener en cuenta que la devolución de llamada finally no afecta el estado de la promesa. No importa el valor que devuelva, la promesa se mantiene en el estado cumplido / rechazado que tenía antes. Por lo tanto, en el ejemplo anterior, la promesa se resolverá con el valor de retorno de processData(result.data) aunque la devolución de llamada finally devolvió undefined .

Con el proceso de normalización sigue siendo en curso, la implementación de las promesas más probable es que no apoyará finally devoluciones de llamada fuera de la caja. Para las devoluciones de llamada sincrónicas, puede agregar esta funcionalidad con un polyfill sin embargo:

if (!Promise.prototype.finally) {
    Promise.prototype.finally = function(callback) {
        return this.then(result => {
            callback();
            return result;
        }, error => {
            callback();
            throw error;
        });
    };
}

Solicitud de API asíncrona

Este es un ejemplo de una simple llamada GET API envuelta en una promesa de aprovechar su funcionalidad asíncrona.

var get = function(path) {
  return new Promise(function(resolve, reject) {
    let request = new XMLHttpRequest();
    request.open('GET', path);
    request.onload = resolve;
    request.onerror = reject;
    request.send();
  });
};

Se puede hacer un manejo de errores más robusto usando las siguientes funciones onload y onerror .

request.onload = function() {
  if (this.status >= 200 && this.status < 300) {
    if(request.response) {
      // Assuming a successful call returns JSON
      resolve(JSON.parse(request.response));
    } else {
      resolve();
  } else {
    reject({
      'status': this.status,
      'message': request.statusText
    });
  }
};

request.onerror = function() {
  reject({
    'status': this.status,
    'message': request.statusText
  });
};

Utilizando ES2017 async / await

El mismo ejemplo anterior, Carga de imagen , puede escribirse usando funciones asíncronas . Esto también permite usar el método común de try/catch para el manejo de excepciones.

Nota: a partir de abril de 2017, las versiones actuales de todos los navegadores, pero Internet Explorer admite funciones asíncronas .

function loadImage(url) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.addEventListener('load', () => resolve(img));
        img.addEventListener('error', () => {
            reject(new Error(`Failed to load ${url}`));
        });
        img.src = url;
    });
}

(async () => {

    // load /image.png and append to #image-holder, otherwise throw error
    try {
        let img = await loadImage('http://example.com/image.png');
        document.getElementById('image-holder').appendChild(img);
    }
    catch (error) {
        console.error(error);
    }

})();


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow