Disons que j'ai du code qui ressemble à ceci:
{ outerList : [ { innerList: [ 2, 3, 4 ] }, { innerList: [ 3, 5, 7 ] } ] };
Et je veux transformer l'objet en ceci:
const myObject = { outerList : [ { innerList: [ 1, 2, 3 ] }, { innerList: [ 2, 4, 6 ] } ] }; async function asyncTransform(i) { return new Promise((resolve) => { setTimeout(() => { resolve(i+1); }, Math.random()* 1000); }); } async function asyncTransformNestedObject(obj) { //??? } asyncTransformNestedObject(myObject).then((result) => { console.log(result); });
Quelle serait la meilleure façon de faire cela - idéalement d'une manière où l'async fonctionne exécuter simultanément.
3 Réponses :
asyncTransform
, puis transmettez ce tableau à Promise.all . Promise.all
chaque Promise.all
créé à l'étape 1. Voici un exemple:
const myObject = { outerList : [ { innerList: [ 1, 2, 3 ] }, { innerList: [ 2, 4, 6 ] } ] } function asyncTransform(i) { return new Promise(resolve => setTimeout(() => resolve(i + 1), 50)) } function asyncTransformNestedObject(obj) { const innerLists = obj.outerList.map(el => { return Promise.all(el.innerList.map(asyncTransform)) .then(results => el.innerList = results) }) return Promise.all(innerLists) .then((results, i) => obj.outerList.map((el, i) => ({ ...el, innerList: results[i] }))) } asyncTransformNestedObject(myObject).then((result) => { console.log(result) })
Notez que vous ne reproduisez pas correctement la structure de l'objet d'origine.
C'est vrai, a ajouté un correctif.
Voici la solution avec laquelle j'ai fini par aller:
C'est assez simple quand on y pense:
Un Promise.all of a Promise.all va se résoudre au moment maximum de toutes les promesses.
const myObject = { outerList : [ { innerList: [ 1, 2, 3 ] }, { innerList: [ 2, 4, 6 ] } ] }; async function asyncTransform(i) { return new Promise((resolve) => { setTimeout(() => { resolve(i+1); }, Math.random()* 1000); }); } async function transformInnerObj(innerObj) { const newInnerList = await Promise.all(innerObj.innerList.map(i => asyncTransform(i))); return { innerList: newInnerList }; } async function asyncTransformNestedObject(obj) { const newOuterList = await Promise.all(obj.outerList.map(innerObj => transformInnerObj(innerObj))); return { outerList: newOuterList }; } asyncTransformNestedObject(myObject).then(result => { console.log(result); });
Mineure: les fonctions qui renvoient explicitement une Promise
, comme asyncTransform
n'ont pas besoin d'être marquées comme async
.
Je résoudrais cela en utilisant un setTimeout / requestAnimationFrame récursif dans ES5, mais si vous insistez sur la fonction async, cela semble faire l'affaire:
async function convert(arr,i = 0){ if(!arr[i]){return arr} await arr[i].innerList.reduce((ac,d,i,a) => ++a[i],(async function(){}())); return convert(arr,++i); } convert(myObject.outerList); //myObject "[ { "innerList": [ 2, 3, 4 ] }, { "innerList": [ 3, 5, 7 ] } ]"
Vous n'avez rien spécifié sur la mutation l'objet d'origine, donc je l'ai changé en place. J'ai également renvoyé le innerArray, vous auriez pu renvoyer l'objet lui-même instean et utiliser await pour stocker dans une variable.
Ce n'est pas mon vote négatif, mais c'est un code assez cryptique.
@dwjohnston, je comprends, np. C'est pourquoi j'ai dit que je résoudrais avec ES5 récursif. J'ai vu que vous mettiez un peu l'accent sur les fonctions async, je me suis donc demandé s'il serait possible d'utiliser uniquement async / await. La partie de réduction consiste à forcer la ligne à renvoyer une promesse résolue avec undefined et à l'attendre pour que tous les éléments du tableau soient incrémentés, si c'est la partie qui était cryptique.
avons-nous vraiment besoin d'une fonction asynchrone ici?
@brk Oui. C'est juste un exemple. Dans la vraie vie, ce sont des appels API.