web-dev-qa-db-fra.com

Promesses JavaScript - rejeter ou rejeter

J'ai lu plusieurs articles sur ce sujet, mais je ne vois toujours pas s'il existe une différence entre Promise.reject et une erreur. Par exemple,

tilisation de Promise.reject

return asyncIsPermitted()
    .then(function(result) {
        if (result === true) {
            return true;
        }
        else {
            return Promise.reject(new PermissionDenied());
        }
    });

tilisation du lancer

return asyncIsPermitted()
    .then(function(result) {
        if (result === true) {
            return true;
        }
        else {
            throw new PermissionDenied();
        }
    });

Ma préférence est d'utiliser throw simplement parce que c'est plus court, mais je me demandais s'il y avait un avantage de l'un sur l'autre.

298
Naresh

Il n'y a aucun avantage à utiliser l'un par rapport à l'autre, mais il existe un cas spécifique dans lequel throw ne fonctionnera pas. Cependant, ces cas peuvent être corrigés.

Chaque fois que vous vous trouvez dans un rappel de promesse, vous pouvez utiliser throw. Toutefois, si vous utilisez un autre rappel asynchrone, vous devez utiliser reject.

Par exemple, cela ne déclenchera pas le piège:

new Promise(function() {
  setTimeout(function() {
    throw 'or nah';
    // return Promise.reject('or nah'); also won't work
  }, 1000);
}).catch(function(e) {
  console.log(e); // doesn't happen
});

Au lieu de cela, vous vous retrouvez avec une promesse non résolue et une exception non capturée. Dans ce cas, vous voudriez utiliser plutôt reject. Cependant, vous pouvez résoudre ce problème en promettant le délai d'attente:

function timeout(duration) { // Thanks joews
  return new Promise(function(resolve) {
    setTimeout(resolve, duration);
  });
}

timeout(1000).then(function() {
  throw 'worky!';
  // return Promise.reject('worky'); also works
}).catch(function(e) {
  console.log(e); // 'worky!'
});
253
Kevin B

Un autre fait important est que reject()NE FAIT PAS termine le flux de contrôle comme le fait une instruction return. En revanche, throw met fin au flux de contrôle.

Exemple:

new Promise((resolve, reject) => {
  throw "err";
  console.log("NEVER REACHED");
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));

contre

new Promise((resolve, reject) => {
  reject(); // resolve() behaves similarly
  console.log("ALWAYS REACHED"); // "REJECTED" will print AFTER this
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));
172
lukyer

Oui, la plus grande différence est que rejeter est une fonction de rappel exécutée après le rejet de la promesse, alors que projection ne peut pas être utilisée de manière asynchrone. Si vous choisissez d'utiliser le rejet, votre code continuera à fonctionner normalement de manière asynchrone alors que throw donnera la priorité à la fonction de résolution (cette fonction sera exécutée immédiatement).

Un exemple que j’ai vu et qui a aidé à clarifier le problème pour moi est que vous pouvez définir une fonction Timeout avec rejet, par exemple:

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

Ce qui précède ne serait pas possible d'écrire avec un lancer.

Dans votre petit exemple, la différence est indiscernable, mais s’il s’agit d’un concept asynchrone plus complexe, la différence entre les deux peut être considérable.

44
Blondie

TLDR: Une fonction est difficile à utiliser lorsqu'elle renvoie parfois une promesse et génère parfois une exception. Lors de l'écriture d'une fonction asynchrone, préférez signaler un échec en retournant une promesse refusée

Votre exemple particulier masque certaines distinctions importantes entre eux:

Comme vous gérez des erreurs dans une chaîne de promesse, les exceptions levées sont automatiquement converties aux promesses refusées. Cela peut expliquer pourquoi ils semblent interchangeables - ils ne le sont pas.

Considérez la situation ci-dessous:

checkCredentials = () => {
    let idToken = localStorage.getItem('some token');
    if ( idToken ) {
      return fetch(`https://someValidateEndpoint`, {
        headers: {
          Authorization: `Bearer ${idToken}`
        }
      })
    } else {
      throw new Error('No Token Found In Local Storage')
    }
  }

Ce serait un anti-modèle car vous auriez alors besoin de prendre en charge les cas d'erreur asynchrones et de synchronisation. Cela pourrait ressembler à quelque chose comme:

try {
  function onFulfilled() { ... do the rest of your logic }
  function onRejected() { // handle async failure - like network timeout }
  checkCredentials(x).then(onFulfilled, onRejected);
} catch (e) {
  // Error('No Token Found In Local Storage')
  // handle synchronous failure
} 

Ce n’est pas bon et c’est exactement là où Promise.reject (disponible dans l’envergure mondiale) vient à la rescousse et se différencie efficacement de throw. Le refactor devient maintenant:

checkCredentials = () => {
  let idToken = localStorage.getItem('some_token');
  if (!idToken) {
    return Promise.reject('No Token Found In Local Storage')
  }
  return fetch(`https://someValidateEndpoint`, {
    headers: {
      Authorization: `Bearer ${idToken}`
    }
  })
}

Cela vous permet désormais d’utiliser un seul catch() pour les défaillances du réseau et la vérification d’erreur synchrone pour manque de jetons:

checkCredentials()
      .catch((error) => if ( error == 'No Token' ) {
      // do no token modal
      } else if ( error === 400 ) {
      // do not authorized modal. etc.
      }
36
maxwell

Un exemple à essayer. Il suffit de changer isVersionThrow en false pour utiliser rejeter au lieu de lancer.

const isVersionThrow = true

class TestClass {
  async testFunction () {
    if (isVersionThrow) {
      console.log('Throw version')
      throw new Error('Fail!')
    } else {
      console.log('Reject version')
      return new Promise((resolve, reject) => {
        reject(new Error('Fail!'))
      })
    }
  }
}

const test = async () => {
  const test = new TestClass()
  try {
    var response = await test.testFunction()
    return response 
  } catch (error) {
    console.log('ERROR RETURNED')
    throw error 
  }  
}

test()
.then(result => {
  console.log('result: ' + result)
})
.catch(error => {
  console.log('error: ' + error)
})
5
Chris Livdahl