28 votes

Rappels de promesses renvoyant des promesses

Quant à ces deux sources: NZakas - Retour de Promesses en Promesses de Chaînes et de MDN Promesses, je voudrais poser les questions suivantes:

Chaque fois que nous le retourner une valeur à partir d'une promesse d'accomplissement gestionnaire, comment est-ce que la valeur passée à la nouvelle promesse retourné par ce même gestionnaire?

Par exemple,

let p1 = new Promise(function(resolve, reject) {
    resolve(42);
});

let p2 = new Promise(function(resolve, reject) {
    resolve(43);
});

let p3 = p1.then(function(value) {
    // first fulfillment handler
    console.log(value);     // 42
    return p2;
});

p3.then(function(value) {
    // second fulfillment handler
    console.log(value);     // 43
});

Dans cet exemple, p2 est une promesse. p3 est aussi une promesse originaires d' p1s'accomplissement de gestionnaire. Toutefois p2 !== p3. Au lieu de cela p2 en quelque sorte comme par magie, décide 43 (comment?) et cette valeur est ensuite transmis à l' p3s'accomplissement de gestionnaire. Même la phrase ici est source de confusion.

Pourriez-vous s'il vous plaît expliquez-moi ce qui se passe exactement ici? Je suis totalement confus sur ce concept.

25voto

Dan Points 16670

Disons que de jeter à l'intérieur d' then() rappel rejette le résultat de la promesse par un échec, et le retour à partir de then() rappel remplit le résultat promesse avec une valeur de succès.

let p2 = p1.then(() => {
  throw new Error('lol')
})
// p2 was rejected with Error('lol')

let p3 = p1.then(() => {
  return 42
})
// p3 was fulfilled with 42

Mais parfois, même à l'intérieur de la poursuite, nous ne savons pas si nous avons réussi ou pas. Nous avons besoin de plus de temps.

return checkCache().then(cachedValue => {
  if (cachedValue) {
    return cachedValue
  }

  // I want to do some async work here
})

Toutefois, si je ne async y travailler, il serait trop tard pour return ou throw, ne serait-il pas?

return checkCache().then(cachedValue => {
  if (cachedValue) {
    return cachedValue
  }

  fetchData().then(fetchedValue => {
    // Doesn't make sense: it's too late to return from outer function by now.
    // What do we do?

    // return fetchedValue
  })
})

C'est pourquoi les Promesses ne serait pas utile si vous ne pouvait pas se résoudre à une autre Promesse.

Cela ne signifie pas que dans votre exemple, p2 serait devenue p3. Ils sont séparés Promesse d'objets. Toutefois, en retournant p2 de then() qui produit p3 que vous dites "je veux p3 se résoudre à ce que p2 résout, qu'elle réussisse ou échoue".

Comme pour la façon dont cela se produit, il est spécifique à l'implémentation. En interne, vous pouvez penser à de la then() que la création d'une nouvelle Promesse. La mise en œuvre seront en mesure de remplir ou de le rejeter à chaque fois qu'il aime. Normalement, il va automatiquement remplir ou de le rejeter, lors de votre retour:

// Warning: this is just an illustration
// and not a real implementation code.
// For example, it completely ignores
// the second then() argument for clarity,
// and completely ignores the Promises/A+
// requirement that continuations are
// run asynchronously.

then(callback) {
  // Save these so we can manipulate
  // the returned Promise when we are ready
  let resolve, reject

  // Imagine this._onFulfilled is an internal
  // queue of code to run after current Promise resolves.
  this._onFulfilled.push(() => {
    let result, error, succeeded
    try {
      // Call your callback!
      result = callback(this._result)
      succeeded = true
    } catch (err) {
      error = err
      succeeded = false
    }

    if (succeeded) {
      // If your callback returned a value,
      // fulfill the returned Promise to it
      resolve(result)
    } else {
      // If your callback threw an error,
      // reject the returned Promise with it
      reject(error)
    }
  })

  // then() returns a Promise
  return new Promise((_resolve, _reject) => {
    resolve = _resolve
    reject = _reject
  })
}

Encore une fois, c'est beaucoup de pseudo-code, mais montre l'idée derrière l' then() pourrait être mise en œuvre dans la Promesse implémentations.

Si nous voulons ajouter le support pour la résolution d'une Promesse, nous avons juste besoin de modifier le code afin de bénéficier d'une branche spéciale si l' callback vous passez then() retourné une Promesse:

    if (succeeded) {
      // If your callback returned a value,
      // resolve the returned Promise to it...
      if (typeof result.then === 'function') {
        // ...unless it is a Promise itself,
        // in which case we just pass our internal
        // resolve and reject to then() of that Promise
        result.then(resolve, reject)
      } else {
        resolve(result)
      }
    } else {
      // If your callback threw an error,
      // reject the returned Promise with it
      reject(error)
    }
  })

Permettez-moi de préciser à nouveau que ce n'est pas une Promesse de la mise en œuvre et a de grands trous et des incompatibilités. Cependant, il devrait vous donner une idée intuitive de la façon dont la Promesse des bibliothèques de mettre en œuvre la résolution d'une Promesse. Après vous êtes à l'aise avec l'idée, je vous recommande de jeter un oeil à la façon dont les Promesses implémentations de gérer cela.

8voto

Vincent Taing Points 470

Fondamentalement, p3 est return-ing une autre promesse : p2. Ce qui signifie que le résultat de l' p2 sera passé en paramètre à la prochaine then rappel, dans ce cas, il décide d' 43.

Chaque fois que vous utilisez le mot-clé return vous êtes de passage le résultat en tant que paramètre à la prochaine then's de rappel.

let p3 = p1.then(function(value) {
    // first fulfillment handler
    console.log(value);     // 42
    return p2;
});

Votre code :

p3.then(function(value) {
    // second fulfillment handler
    console.log(value);     // 43
});

Est égale à:

p1.then(function(resultOfP1) {
    // resultOfP1 === 42
    return p2; // // Returning a promise ( that might resolve to 43 or fail )
})
.then(function(resultOfP2) {
    console.log(resultOfP2) // '43'
});

Btw, j'ai remarqué que vous utilisez ES6 syntaxe, vous pouvez avoir un briquet de la syntaxe à l'aide de fat flèche de la syntaxe :

p1.then(resultOfP1 => p2) // the `return` is implied since it's a one-liner
.then(resultOfP2 => console.log(resultOfP2)); 

3voto

Thomas Points 1659

Dans cet exemple, p2 est une promesse. p3 est aussi une promesse originaires de p1 d'exécution de gestionnaire. Cependant p2 !== p3. Au lieu de p2 en quelque sorte comme par magie résout à 43 (comment?) et cette valeur est ensuite transmis à p3 d'exécution de gestionnaire. Même la phrase ici est source de confusion.

une version simplifiée de la façon dont cela fonctionne (seulement pseudocode)

function resolve(value){
    if(isPromise(value)){
        value.then(resolve, reject);
    }else{
        //dispatch the value to the listener
    }
}

le tout est bien plus compliqué puisque vous avez à prendre soin, si la promesse a déjà été résolu et qu'un peu plus de choses.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X