web-dev-qa-db-fra.com

Promise constructeur avec rejeter appel vs erreur de projection

Dans le code suivant:

var p1 = new Promise(function (resolve, reject) {
    throw 'test1';
});

var p2 = new Promise(function (resolve, reject) {
    reject('test2');
});

p1.catch(function (err) {
    console.log(err); // test1
});

p2.catch(function (err) {
    console.log(err); // test2
});

Existe-t-il une différence entre utiliser reject (dans p2) à partir de l'API Promise et générer une erreur (dans p1) en utilisant throw

C'est exactement pareil?

Si c'est la même chose, pourquoi avons-nous besoin d'un rappel reject alors?

54
lante

Existe-t-il une différence entre utiliser reject (dans p2) à partir de l'API Promise et générer une erreur (dans p1) en utilisant throw

Oui, vous ne pouvez pas utiliser throw de manière asynchrone, alors que reject est un rappel. Par exemple, un délai d'attente:

new Promise(_, reject) {
    setTimeout(reject, 1000);
});

C'est exactement pareil?

Non, du moins pas lorsqu'un autre code suit votre déclaration. throw termine immédiatement la fonction de résolution, tandis que l'appel de reject continue son exécution normalement - après avoir "marqué" la promesse comme rejetée.

En outre, les moteurs peuvent fournir des informations de débogage des exceptions différentes si vous throw objets d'erreur.

Pour votre exemple spécifique, vous avez raison de dire que p1 et p2 sont impossibles à distinguer de l'extérieur.

58
Bergi

Non, il n'y en a pas, les deux sont complètement identiques. La seule différence et la raison pour laquelle nous avons besoin de reject est lorsque vous devez rejeter de manière asynchrone. Par exemple, si vous convertissez une API basée sur le rappel, il peut être nécessaire de signaler une erreur asynchrone.

var p = new Promise(function(resolve, reject){
    someCallbackApi(function(err, data){
        if(err) reject(err); // CAN'T THROW HERE, non promise context, async.
        else resolve(data);
    });
});
31
Benjamin Gruenbaum

Je sais que c'est un peu tard, mais je ne pense pas que l'une ou l'autre de ces réponses réponde complètement aux questions que j'avais quand j'ai trouvé ceci. Voici un exemple plus complet à jouer.

var p1 = new Promise(function (resolve, reject) {
    throw 'test 1.1'; //This actually happens
    console.log('test 1.1.1'); //This never happens
    reject('test 1.2'); //This never happens because throwing an error already rejected the promise
    console.log('test 1.3'); //This never happens
});

var p2 = new Promise(function (resolve, reject) {
    reject('test 2.1'); //This actually happens
    console.log('test 2.1.1'); //This happens BEFORE the Promise is rejected because reject() is a callback
    throw 'test 2.2'; //This error is caught and ignored by the Promise
    console.log('test 2.3'); //This never happens
});

var p3 = new Promise(function (resolve, reject) {
    setTimeout(function() { reject('test 3.1');}, 1000); //This never happens because throwing an error already rejected the promise
    throw('test 3.2'); //This actually happens
    console.log('test 3.3'); //This never happens
});

var p4 = new Promise(function (resolve, reject) {
    throw('test 4.1'); //This actually happens
    setTimeout(function() { reject('test 4.2');}, 1000); //This never happens because throwing an error already rejected the promise
    console.log('test 4.3'); //This never happens
});

var p5 = new Promise(function (resolve, reject) {
    setTimeout(function() { throw('test 5.1');}, 1000); //This throws an Uncaught Error Exception
    reject('test 5.2'); //This actually happens
    console.log('test 5.3'); //This happens BEFORE the Promise is rejected because reject() is a callback
});

var p6 = new Promise(function (resolve, reject) {
    reject('test 6.1'); //This actually happens
    setTimeout(function() { throw('test 6.2');}, 1000); //This throws an Uncaught Error Exception
    console.log('test 6.3'); //This happens BEFORE the Promise is rejected because reject() is a callback
});


p1.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test1
});

p2.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test2
});

p3.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test3
});

p4.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test4
});

p5.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test5
});

p6.then(function (resolve) {
    console.log(resolve, "resolved")
}, function (reject) {
    console.log(reject, "rejected")
}).catch(function (err) {
    console.log(err, "caught"); // test6
});

28
Jonathan Rys

Une observation très intéressante est que si vous utilisez throw, il sera d'abord géré par le gestionnaire reject, puis par le gestionnaire error si aucun gestionnaire de rejet n'est en place.

Avec bloc de gestion des rejets

var allowed = false;
var p1 = new Promise(
function(resolve, reject) {
  if (allowed)
    resolve('Success');
  else
//         reject('Not allowed');
    throw new Error('I threw an error')
})

p1.then(function(fulfilled) {
console.log('Inside resolve handler, resolved value: ' + fulfilled);
}, function(rejected) {
console.log('Inside reject handler, rejected value: ' + rejected);
}).catch(function(error) {
console.log('Inside error handler, error value: ' + error);
})

Sans bloc de gestion des rejets

var allowed = false;
var p1 = new Promise(
function(resolve, reject) {
  if (allowed)
    resolve('Success');
  else
//         reject('Not allowed');
    throw new Error('I threw an error')
})

p1.then(function(fulfilled) {
console.log('Inside resolve handler, resolved value: ' + fulfilled);
}).catch(function(error) {
console.log('Inside error handler, error value: ' + error);
})

De plus, le bloc catch pourra capturer toute erreur renvoyée dans le gestionnaire resolve .

var allowed = true;
var p1 = new Promise(
function(resolve, reject) {
  if (allowed)
    resolve('Success');
  else
//         reject('Not allowed');
    throw new Error('I threw an error')
})

p1.then(function(fulfilled) {
console.log('Inside resolve handler, resolved value: ' + fulfilled);
throw new Error('Error created inside resolve handler block');
}).catch(function(error) {
console.log('Inside error handler, error value: ' + error);
})

Il semble préférable d'utiliser throw, sauf si vous ne le pouvez pas si vous exécutez une tâche asynchrone, vous devrez transmettre le rappel reject à la fonction async. Mais il y a un moyen de contourner le problème, c'est de promettre votre fonction asynchrone. Plus d'informations sur https://stackoverflow.com/a/33446005

0
Gavin