web-dev-qa-db-fra.com

async / wait renvoie implicitement la promesse?

J'ai lu que les fonctions asynchrones marquées par le mot clé async renvoient implicitement une promesse:

async function getVal(){
 return await doSomethingAync();
}

var ret = getVal();
console.log(ret);

mais ce n'est pas cohérent ... en supposant que doSomethingAsync() renvoie une promesse, et le mot-clé wait retournera la valeur de la promesse, pas la promesse itsef, alors ma fonction getVal devrait return cette valeur, pas une promesse implicite.

Alors, quel est exactement le cas? Les fonctions marquées par le mot clé async renvoient-elles implicitement les promesses ou contrôlons-nous ce qu'elles renvoient?

Peut-être que si nous ne retournons pas explicitement quelque chose, ils renvoient implicitement une promesse ...?

Pour être plus clair, il y a une différence entre ce qui précède et

function doSomethingAync(charlie) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(charlie || 'yikes');
        }, 100);
    })
}

async function getVal(){
   var val = await doSomethingAync();  // val is not a promise
   console.log(val); // logs 'yikes' or whatever
   return val;  // but this returns a promise
}

var ret = getVal();
console.log(ret);  //logs a promise

Dans mon résumé, le comportement est en effet incompatible avec les instructions de retour traditionnelles. Il semble que lorsque vous renvoyez explicitement une valeur non-promise d'une fonction async, il sera forcé de l'envelopper dans une promesse. Je n'ai pas de gros problème avec ça, mais ça défie JS normal.

79
Alexander Mills

La valeur de retour sera toujours une promesse. Si vous ne retournez pas explicitement une promesse, la valeur que vous retournez sera automatiquement encapsulée dans une promesse.

async function increment(num) {
  return num + 1;
}

// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));

Même chose même s'il y a un await.

function defer(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(callback());
    }, 1000);
  });
}

async function incrementTwice(num) {
  const numPlus1 = await defer(() => num + 1);
  return numPlus1 + 1;
}

// Logs: 5
incrementTwice(3).then(num => console.log(num));

Les promesses se déroulent automatiquement. Ainsi, si vous retournez une promesse pour une valeur à partir d'une fonction async, vous recevrez une promesse pour la valeur (et non une promesse d'une promesse pour la valeur).

function defer(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      resolve(callback());
    }, 1000);
  });
}

async function increment(num) {
  // It doesn't matter whether you put an `await` here.
  return defer(() => num + 1);
}

// Logs: 4
increment(3).then(num => console.log(num));

Dans mon résumé, le comportement est en effet incompatible avec les instructions de retour traditionnelles. Il semble que lorsque vous renvoyez explicitement une valeur non-promise d'une fonction asynchrone, il sera forcé de l'envelopper dans une promesse. Je n'ai pas de gros problème avec ça, mais ça défie JS normal.

ES6 a des fonctions qui ne renvoient pas exactement la même valeur que return. Ces fonctions sont appelées générateurs.

function* foo() {
  return 'test';
}

// Logs an object.
console.log(foo());

// Logs 'test'.
console.log(foo().next().value);
93
Nathan Wall

J'ai jeté un coup d'oeil à la spécification et trouvé les informations suivantes. La version courte est qu'un async function desugars à un générateur qui donne Promises. Donc, oui, les fonctions asynchrones renvoient des promesses .

Selon tc39 spec , ce qui suit est vrai:

async function <name>?<argumentlist><body>

Desugars to:

function <name>?<argumentlist>{ return spawn(function*() <body>, this); }

spawn "est un appel à l'algorithme suivant":

function spawn(genF, self) {
    return new Promise(function(resolve, reject) {
        var gen = genF.call(self);
        function step(nextF) {
            var next;
            try {
                next = nextF();
            } catch(e) {
                // finished with failure, reject the promise
                reject(e);
                return;
            }
            if(next.done) {
                // finished with success, resolve the promise
                resolve(next.value);
                return;
            }
            // not finished, chain off the yielded promise and `step` again
            Promise.resolve(next.value).then(function(v) {
                step(function() { return gen.next(v); });
            }, function(e) {
                step(function() { return gen.throw(e); });
            });
        }
        step(function() { return gen.next(undefined); });
    });
}
17
Jon Surrell