2017-10-19 3 views
3

Recherche de "Uncaught (en promesse)" dans les problèmes de github d'Angular, google ou ici sur stackoverflow donne beaucoup de très résultats spécifiques, mais ma question est un peu plus large (et depuis la prolifération des résultats, je ne sais pas s'il s'agit d'un doublon)Pourquoi rejet() d'une nouvelle Promesse perd la trace de la pile dans l'erreur redoutée "Uncaught (en promesse)"

Prémisse: quelque part dans mon code j'ai un rejet de promesse non pris (Angular 4.4. 4)

cas:

cas 1: Rejet simple

En MyComponent:

ngOnInit() { 
    Promise.reject("foo"); 
} 

Rendements cela dans la console (grande, je peux voir d'où il vient):

ERROR Error: Uncaught (in promise): foo 
    at resolvePromise (zone.js:824) 
    at Function.ZoneAwarePromise.reject (zone.js:903) 
    at MyComponent.webpackJsonp.../../../../../src/app/component/my.component.ts.MyComponent.ngOnInit (my.component.ts:nn) 

Cas n ° 2: nouvelle promesse, jeter une erreur

Dans MonComposant:

ngOnInit() { 
    new Promise((resolve, reject) => { 
    throw new Error("foo"); 
    }).then(() => { 
    console.log("ain't gonna happen"); 
    }); 
} 

Rendements cela dans la console (encore mieux, donne suite à la situation sur place):

ERROR Error: Uncaught (in promise): Error: foo 
Error: foo 
    at my.component.ts:nn 
    at new ZoneAwarePromise (zone.js:890) 
    at MyComponent.webpackJsonp.../../../../../src/app/component/my.component.ts.LMyComponent.ngOnInit (my.component.ts:nn) 

Cela fonctionne aussi avec Enchaînement, par exemple Ce qui suit donne plus ou moins la même trace de pile dans la console.

ngOnInit() { 


    const promise3 = new Promise((resolve, reject) => { 
    throw new Error("baz"); 
    }); 
    const promise2 = new Promise((resolve, reject) => { 
    resolve(promise3); 
    }); 

    const promise1 = new Promise((resolve, reject) => { 
    resolve(promise2); 
    }); 

    promise1.then(p1=> console.log(p1)); 
} 

Cas n ° 3: Utilisation de rejeter (...)

En MyComponent:

ngOnInit() { 
    new Promise((resolve, reject) => { 
    reject("foo"); 
    }).then(() => { 
    console.log("ain't gonna happen"); 
    }); 
} 

Modification de lancer une erreur au (je suppose que la pratique assez courante) d'utiliser la méthode de rejet de la promesse, donne cette horreur:

core.es5.js:1020 ERROR Error: Uncaught (in promise): baz 
    at resolvePromise (zone.js:824) 
    at resolvePromise (zone.js:795) 
    at zone.js:873 
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:425) 
    at Object.onInvokeTask (core.es5.js:3881) 
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424) 
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask (zone.js:192) 
    at drainMicroTaskQueue (zone.js:602) 
    at <anonymous> 

Question

  1. Pourquoi ne puis-je voir la trace de la pile ou l'origine de l'erreur cette fois-ci? (Je suppose que c'est simplement parce que JavaScript génère seulement la trace de la pile depuis l'emplacement de l'erreur lancée?)

  2. Si oui, est-ce une mauvaise pratique d'utiliser le rejet explicite plutôt que de lancer une nouvelle erreur dans une nouvelle promesse? Est-ce documenté quelque part et je l'ai manqué?

  3. Y at-il un moyen de résoudre ce problème? (Obtenir la trace de la pile et continuer à rejeter (...) au lieu de lancer une erreur ?, Je suppose non)

  4. Est-ce un problème/une mauvaise pratique et j'ai raté le mémo?

+0

Essayez 'reject (nouvelle erreur (" foo "))'. [Ne jamais rejeter avec des erreurs] (https://stackoverflow.com/q/26020578/1048572). – Bergi

+0

Quelle implémentation promesse utilisez-vous? – Bergi

+0

En ce qui concerne la question 2: https://stackoverflow.com/a/28703407/1048572 – Bergi

Répondre

0

répondre en partie à un de mes propres questions:

Si je change le cas n ° 3 à ceci: (emballage dans un nouvel objet d'erreur)

ngOnInit() { 
    new Promise((resolve, reject) => { 
    reject(new Error("foo")); 
    }).then(() => { 
    console.log("ain't gonna happen"); 
    }); 
} 

Alors, surprise, surprise, je Obtenez la trace de la pile! (Construire simplement une erreur sauve la trace de la pile)

Sur une note de côté ... puisque (je suppose) la plupart d'entre nous préfèrent voir une trace de pile par rapport à non, alors pourquoi oh pourquoi n'est-ce pas mentionné comme un les meilleures pratiques ici ?: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Modifier

Pour vous assurer que je n'oublie pas, j'ajouté ce rétrécissement (reject: (reason: Error) => void au lieu de any), pas sûr si cela est une excellente solution car il ne protéger de passer any, mais il peut aider à protéger certains des cas de ne pas passer un Error à rejeter.

export {} 

declare global { 

    interface PromiseConstructor { 
    /** 
    * A reference to the prototype. 
    */ 
    readonly prototype: Promise<any>; 

    /** 
    * Creates a new Promise. 
    * @param executor A callback used to initialize the promise. This callback is passed two arguments: 
    * a resolve callback used resolve the promise with a value or the result of another promise, 
    * and a reject callback used to reject the promise with a provided reason or error. 
    */ 
    new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason: Error) => void) => void): Promise<T>; 

    } 
} 
+0

Oups, n'a pas vu le commentaire de @ Bergi qui a dit exactement cela. Garder la clarté ... –