2016-12-01 1 views
0

Je suis curieux de savoir comment puis-je utiliser les promesses bluebird dans mon code javascript existant qui utilise beaucoup de mécanisme basé sur le rappel. Voici le scénario:Comment appliquer les promesses bluebird à ma traversée javascript existante et à la logique récursive?

Dans mon application web au chargement de la page en utilisant jQuery, j'obtiendrai les liens du menu principal de la page et je générerai une structure TreeModel que j'utiliserai plus tard pour afficher un fil d'Ariane en haut de la page.

La fonction que je utilise pour générer cette TreeModel suit:

function _traverseNodeChildren(selector, parentNode, callback1, callback2) { 

    $(parentNode.model.element).find(selector).each(function(idx, elm) { 

     // Create a Tree Node using TreeModel 
     let node = _createTreeNode.apply(this.comp, [elm]); 
     this.parentNode.addChild(node); 

     let hasChildren = $(elm).find("+ul.dropdown-menu").length > 0; 
     if (hasChildren == true) 
      _traverseNodeChildren.apply(this.comp, ["+ul.dropdown-menu > li > a", node, callback1, callback2]); 

     if (node.model.id == "aboutLink") // last node 
     { 
      setTimeout(() => { 
       callback1.apply(this.comp, [callback2]); 
      }, 100); 
     } 
    }.bind({parentNode: parentNode, comp: this})); 
} 

Après terminé traversal ci-dessus, je veux appeler la fonction myServerCall qui impliquera une async Ajax demande et après l'achèvement de cette demande async, Enfin, je veux appeler une troisième fonction myFinalFunc.

À l'heure actuelle, je suis en utilisant le code suivant pour rendre ce code traversal Execute:

const TreeModel = require('tree-model'); 
const _treeModel = new TreeModel(); 

let _bcRoot = _treeModel.parse({ 
    id: "0", 
    href: null, 
    text: "", 
    element: $(".main-menu").get(0) 
}); 

_traverseNodeChildren.apply(this, ["> li > a[data-bc-id]", 
      _bcRoot, myServerCall, myFinalFunc]); 

Mais je voudrais qu'il soit converti en approche basée sur la promesse Bluebird pour obtenir plus de contrôle sur elle.

Voici le code que je veux que ce fût à la fin:

_traverseNodeChildren.apply(this, ["> li > a[data-bc-id]", _bcRoot]) 
    .then(function() { 
     return myServerCall(); 
    }) 
    .then(function() { 
     return myFinalFunc(); 
    }) 
    .catch(function(error) { 

    }); 

Comment puis-je faire cela en utilisant Bluebird?

+0

Qu'est-ce que 'callback1', qu'est' callback2'? Pourquoi utilisez-vous 'setTimeout' dans' _traverseNodeChildren', il ne semble rien faire d'asynchrone? – Bergi

+0

Pourquoi tous ces appels 'apply'? Vos instances cibles ne possèdent-elles pas les méthodes respectives? – Bergi

+0

@bergi C'est en fait une sorte de pseudo-code. En ce qui concerne callback1 n callback2 avez-vous lu ma question complète? Ce sont 'myServerCall' et' myFinalFunc'. Et ces deux fonctions seront asynchrones –

Répondre

1

Je vais commencer par simplifier votre code de rappel à

function traverseNodeChildren(comp, selector, parentNode, callback) { 
    $(parentNode.model.element).find(selector).each(function(_, elm) { 
     // Create a Tree Node using TreeModel 
     let node = createTreeNode(comp, elm); 
     parentNode.addChild(node); 

     let hasChildren = $(elm).find("+ul.dropdown-menu").length > 0; 
     if (hasChildren) 
      _traverseNodeChildren(comp, "+ul.dropdown-menu > li > a", node, callback); 

     if (node.model.id == "aboutLink") 
      setTimeout(function() { 
       callback(comp); 
      }, 100); 
     } 
    }); 
} 

traverseNodeChildren(this, "> li > a[data-bc-id]", _bcRoot, function(comp) { 
    myServerCall.call(comp, myFinalFunc) 
}); 

Cependant, étant donné que callback est potentiellement appelé plusieurs fois (quand il y a plusieurs aboutLinks), vous ne pouvez pas vraiment convertir en promesses. Sauf si vous voulez qu'il se comporte différemment.
S'il n'y a qu'un seul lien aboutLink, vous n'avez pas du tout besoin de l'asynchronisme et des rappels dans votre fonction de parcours. Il suffit de faire

function traverseNodeChildren(comp, selector, parentNode) { 
    $(parentNode.model.element).find(selector).each(function(_, elm) { 
     // Create a Tree Node using TreeModel 
     let node = createTreeNode(comp, elm); 
     parentNode.addChild(node); 

     let hasChildren = $(elm).find("+ul.dropdown-menu").length > 0; 
     if (hasChildren) 
      _traverseNodeChildren(comp, "+ul.dropdown-menu > li > a", node); 
    }); 
} 

traverseNodeChildren(this, "> li > a[data-bc-id]", _bcRoot); 
setTimeout(function() { 
    myServerCall(myFinalFunc) 
}, 100); 

que vous maintenant facilement pouvez convertir en Bluebird sans même toucher traverseNodeChildren:

traverseNodeChildren(this, "> li > a[data-bc-id]", _bcRoot); 
Promise.delay(100) 
.then(myServerCall) 
.then(myFinalFunc) 
.catch(function(err) { … }); 

Si vous voulez une sorte de traversal retardée qui attend sur chaque nœud, vous pouvez utiliser

function traverseNodeChildren(comp, selector, parentNode) { 
    return Promise.mapSeries($(parentNode.model.element).find(selector), function(elm) { 
     // Create a Tree Node using TreeModel 
     let node = createTreeNode(comp, elm); 
     parentNode.addChild(node); 

     let hasChildren = $(elm).find("+ul.dropdown-menu").length > 0; 
     if (hasChildren) 
      return _traverseNodeChildren(comp, "+ul.dropdown-menu > li > a", node); 
     else 
      return Promise.delay(100); 
    }); 
} 

traverseNodeChildren(this, "> li > a[data-bc-id]", _bcRoot) 
.then(myServerCall) 
.then(myFinalFunc) 
.catch(function(err) { … }); 
+0

Il n'y a qu'un seul lien aboutLink dans le menu principal de la page et ce sera le dernier nœud de la traversée. –

+0

Alors pourquoi avez-vous donné un rappel à la traversée? Parcourez simplement le menu de manière synchrone, puis démarrez le timeout. – Bergi

+0

Btw, avez-vous vraiment besoin de passer 'this.comp' dans le rappel? – Bergi