J'ai les codes suivants:

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class simplePromise {
  
  constructor(callback) {
    this.state = PENDING;
    this.value = null;
    // here so I can execute all the functions
    this.handlers = [];
    this.doResolve(callback, this.resolve.bind(this), this.reject.bind(this));
  }

  doResolve(callback, onResolved, onRejected) {
    let done = false;
    console.log(callback, 'callback')
    callback((val) => {
      console.log(val, 'val')
      if (done) return;
      done = true;
      onResolved(val)
    })
  }

  resolve(val) {
    this.state = FULFILLED;
    this.value = val;
    this.handlers.forEach(handler => handler);
  }

  reject(error) {
    this.state = REJECTED;
    this.value = error;
    this.handlers.forEach(handler => handler);
  }
}


const promiseA = new simplePromise( (resolutionFunc, rejectionFunc) => {
  resolutionFunc(777);
});

Ce qui me laisse perplexe, ce sont les lignes suivantes:

callback((val) => {
      console.log(val, 'val')

La valeur de val est correctement 777. Cependant, je ne comprends pas pourquoi. D'après ce que j'ai compris, je transmettais à l'origine une fonction de rappel avec 2 arguments, donc j'ai pensé que val aurait la valeur de

(resolutionFunc, rejectionFunc) => {
  resolutionFunc(777);
}

Comment détermine-t-il correctement la valeur dans ce cas comme étant 777?

2
Heymanyoulookkindacool 12 févr. 2021 à 06:43

1 réponse

Meilleure réponse

C'est une très bonne question ... Et moi, il faut des nerfs pour tenter une réponse claire. J'ai peur de devoir éditer 400 fois pour améliorer ce premier brouillon rapide. Espérons que cela restera un brouillon, mais il suffira de passer à d'autres tutoriels approfondis par la suite.


Premièrement, il s'agit vraiment d'une , car tel quel, il ne peut tout simplement pas être rejeté.

Vous avez correctement identifié ce qu'on appelle ici callback ... C'est la fonction passée à l'instance simplePromise.

Notez maintenant que dans le constructeur de promesse, il y a un appel de fonction:

this.doResolve(callback, this.resolve.bind(this), this.reject.bind(this));

callback est passé comme 1er argument et l'autre argument respectivement sont les fonctions resolve et reject définies comme méthodes de la classe. doResolve s'exécute immédiatement à l'instanciation de la promesse.

Donc en exécutant doResolve, le callback est appelé ... Encore une fois en lui passant une fonction comme premier argument:

(val) => {
  console.log(val, 'val')
  if (done) return;
  done = true;
  onResolved(val)
}

Cette fonction, en fait, est l'argument resolutionFunc du callback qui a été fourni à la promesse!

Tellement amusant ... Tellement amusant ...

Restez avec moi! Nous sommes donc toujours à l'exécution de callback ... Et nous appelons resolutionFunc avec 777 comme argument. Nous aurions pu passer une fonction rejectionFunc aussi.

Et c'est là que nous exécutons enfin:

(val) => {
  console.log(val, 'val')
  if (done) return;
  done = true;
  onResolved(val)
}

C'est pourquoi la journalisation de la console val génère 777 ... Cela n'est jamais allé nulle part ailleurs. Il a été transmis directement depuis resolutionFunc(777).

Est-ce donc juste un ensemble de fonctions passées comme fonction à s'appeler elles-mêmes? En bref?

Oui ... Mais il y a un avantage à cela. L'avantage de la "structure" de la promesse est d'avoir tout un ensemble de fonctions bien plus complexes, qui seraient répétitives autrement, dans un class et ne passeraient que la partie changeante du "cas d'utilisation réel" (le callback).

Il permet d'avoir un mécanisme répétitif à l'écart du reste de la logique lors de la programmation.

Il y a aussi un objet lié à l'instance, notamment le state qui pourrait être utilisé par .done(), .fail() etc ... Ainsi, une logique plus complexe peut être chaînée en utilisant l'objet.

Ce qui manque dans cette promesse trop simple ... Est-ce que fait vraiment quelque chose de côté, il suffit de renvoyer la valeur fournie intacte. Cela pourrait être une vérification s'il s'agit d'un nombre ... Ou une vérification de la réponse du serveur, si vous pensez à Ajax par exemple.


Ci-dessous, je viens d'ajouter quelques journaux de console avec des nombres ... Vous pouvez donc remarquer l'ordre d'exécution. ;)

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

class simplePromise {
  
  constructor(callback) {
    this.state = PENDING;
    this.value = null;
    // here so I can execute all the functions
    this.handlers = [];
    this.doResolve(callback, this.resolve.bind(this), this.reject.bind(this));
  }

  doResolve(callback, onResolved, onRejected) {
    console.log("1")
    console.log(callback)
    let done = false;
    callback((val) => {
      console.log("2")
      if (done) return;
      done = true;
      onResolved(val)
    })
  }

  resolve(val) {
    console.log("3")
    this.state = FULFILLED;
    this.value = val;
    this.handlers.forEach(handler => handler);
  }

  reject(error) {
    console.log("4")
    this.state = REJECTED;
    this.value = error;
    this.handlers.forEach(handler => handler);
  }
}


const promiseA = new simplePromise( (resolutionFunc, rejectionFunc) => {
  console.log("5")
  console.log(resolutionFunc)
  resolutionFunc(777);
});

Pourquoi 5 est-il connecté avant 2?

Parce que console.log("2") est à l'intérieur d'une instruction de fonction qui est passée en argument. Et cette fonction est appelée à l'intérieur de callback juste après console.log("5")

resolutionFunc est:

(val) => {
  console.log("2")
  if (done) return;
  done = true;
  onResolved(val)
}

La clé est de remarquer le moment où une instruction de fonction est appelée. J'ai ajouté deux journaux de console à l'extrait de code ... dans l'espoir de le rendre évident.

0
Louys Patrice Bessette 13 févr. 2021 à 19:25