Je viens de lire cet article fantastique -
https://www.promisejs.org/generators/
et il met clairement en évidence cette fonction, qui est une fonction d'aide à la gestion des fonctions du générateur:
function async(makeGenerator){
return function () {
var generator = makeGenerator.apply(this, arguments);
function handle(result){
// result => { done: [Boolean], value: [Object] }
if (result.done) return Promise.resolve(result.value);
return Promise.resolve(result.value).then(function (res){
return handle(generator.next(res));
}, function (err){
return handle(generator.throw(err));
});
}
try {
return handle(generator.next());
} catch (ex) {
return Promise.reject(ex);
}
}
}
que je suppose est plus ou moins la façon dont le mot clé async est implémenté avec async/await
. La question est donc, si tel est le cas, quelle est la différence entre le mot clé await
et le mot clé yield
? await
transforme-t-il toujours quelque chose en promesse, alors que yield
ne donne aucune telle garantie? C'est ma meilleure supposition!
Vous pouvez également voir à quel point async/wait ressemble à un rendement avec des générateurs dans cet article où il décrit la fonction 'spawn': https://jakearchibald.com/2014/es7-async-functions/
Eh bien, il s’avère qu’il existe une relation très étroite entre async/wait et générateurs. Et je crois qu'async/wait sera toujours construit sur des générateurs. Si vous regardez la façon dont Babel transforme Async/wait:
Babel prend ceci:
this.it('is a test', async function () {
const foo = await 3;
const bar = await new Promise(function (resolve) {
resolve('7');
});
const baz = bar * foo;
console.log(baz);
});
et le transforme en cette
function _asyncToGenerator(fn) {
return function () {
var gen = fn.apply(this, arguments);
return new Promise(function (resolve, reject) {
function step(key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(function (value) {
return step("next", value);
}, function (err) {
return step("throw", err);
});
}
}
return step("next");
});
};
}
this.it('is a test', _asyncToGenerator(function* () { // << now it's a generator
const foo = yield 3; // << now it's yield not await
const bar = yield new Promise(function (resolve) {
resolve('7');
});
const baz = bar * foo;
console.log(baz);
}));
vous faites le calcul.
Cela donne l’impression que le mot-clé asynchrone n’est que cette fonction d’emballage, mais si c’est le cas, le temps d’attendre devient alors un rendement, il y aura probablement un peu plus de détails plus tard, quand ils seront natifs.
yield
peut être considéré comme la pierre angulaire de await
. yield
prend la valeur qui lui est attribuée et la transmet à l'appelant. L'appelant peut alors faire ce qu'il veut avec cette valeur (1). Plus tard, l'appelant peut redonner au générateur une valeur (via generator.next()
) qui devient le résultat de l'expression yield
(2), ou une erreur qui semble provenir de l'expression yield
(3).
async
-await
peut être considéré comme utilisant yield
. En (1), l'appelant (c'est-à-dire le pilote async
-await
- similaire à la fonction que vous avez publiée) encapsulera la valeur dans une promesse en utilisant un algorithme similaire à new Promise(r => r(value)
(remarque, pas Promise.resolve
, mais ce n'est pas grave ). Il attend ensuite que la promesse soit résolue. S'il remplit, il renvoie la valeur remplie à (2). S'il refuse, le motif de rejet est considéré comme une erreur en (3).
Donc, l'utilité de async
-await
est cette machine qui utilise yield
pour déballer la valeur générée sous forme de promesse et renvoyer sa valeur résolue, en répétant jusqu'à ce que la fonction retourne sa valeur finale.
quelle est la différence entre le mot clé
await
et le mot cléyield
?
Le mot clé await
ne doit être utilisé que dans async function
s, tandis que le mot clé yield
ne doit être utilisé que dans le générateur function*
s. Et ceux-ci sont évidemment différents aussi: l'un retourne des promesses, l'autre renvoie des générateurs.
await
transforme-t-il toujours quelque chose en promesse, alors queyield
ne donne aucune telle garantie?
Oui, await
appellera Promise.resolve
sur la valeur attendue.
yield
ne donne que la valeur en dehors du générateur.
Utiliser Async/Attendre 99% du temps sur les générateurs. Pourquoi?
Async/Await remplace directement le flux de travail le plus courant des chaînes de promesses permettant au code d'être déclaré comme s'il était synchrone, ce qui le simplifie considérablement.
Les générateurs font abstraction du cas d'utilisation dans lequel vous appelez une série d'opérations asynchrones qui dépendent les unes des autres et finissent par être dans un état "terminé". L'exemple le plus simple consisterait à parcourir les résultats qui renverraient éventuellement le dernier ensemble, mais vous n'appelleriez une page qu'au besoin, pas immédiatement l'un après l'autre.
Async/Await est en réalité une abstraction construite sur des générateurs pour faciliter le travail avec les promesses.
Voir l'explication très détaillée d'Async/Await vs. Generators
Essayez ces programmes de test que je comprenais attendre/async avec des promesses
Programme n ° 1: sans promesses, il ne s'exécute pas en séquence
function functionA() {
console.log('functionA called');
setTimeout(function() {
console.log('functionA timeout called');
return 10;
}, 15000);
}
function functionB(valueA) {
console.log('functionB called');
setTimeout(function() {
console.log('functionB timeout called = ' + valueA);
return 20 + valueA;
}, 10000);
}
function functionC(valueA, valueB) {
console.log('functionC called');
setTimeout(function() {
console.log('functionC timeout called = ' + valueA);
return valueA + valueB;
}, 10000);
}
async function executeAsyncTask() {
const valueA = await functionA();
const valueB = await functionB(valueA);
return functionC(valueA, valueB);
}
console.log('program started');
executeAsyncTask().then(function(response) {
console.log('response called = ' + response);
});
console.log('program ended');
function functionA() {
return new Promise((resolve, reject) => {
console.log('functionA called');
setTimeout(function() {
console.log('functionA timeout called');
// return 10;
return resolve(10);
}, 15000);
});
}
function functionB(valueA) {
return new Promise((resolve, reject) => {
console.log('functionB called');
setTimeout(function() {
console.log('functionB timeout called = ' + valueA);
return resolve(20 + valueA);
}, 10000);
});
}
function functionC(valueA, valueB) {
return new Promise((resolve, reject) => {
console.log('functionC called');
setTimeout(function() {
console.log('functionC timeout called = ' + valueA);
return resolve(valueA + valueB);
}, 10000);
});
}
async function executeAsyncTask() {
const valueA = await functionA();
const valueB = await functionB(valueA);
return functionC(valueA, valueB);
}
console.log('program started');
executeAsyncTask().then(function(response) {
console.log('response called = ' + response);
});
console.log('program ended');
À bien des égards, les générateurs sont un sur-ensemble d'async/wait. Actuellement, async/wait a des traces de pile plus propres que co , la librairie la plus populaire basée sur un générateur async/wait-like. Vous pouvez implémenter votre propre style async/wait en utilisant des générateurs et ajouter de nouvelles fonctionnalités, telles que la prise en charge intégrée de yield
sur des promesses non tenues ou la construction sur des observables RxJS.
En bref, les générateurs vous offrent plus de flexibilité et les bibliothèques basées sur des générateurs ont généralement plus de fonctionnalités. Mais async/wait est une partie essentielle du langage, il est standardisé et ne changera pas, et vous n’avez pas besoin d’une bibliothèque pour l’utiliser. J'ai un article blog avec plus de détails sur la différence entre async/wait et les générateurs.