2017-10-18 14 views
1

J'utilise un module node.js qui a une méthode sans callbacks. Au lieu de cela, a un événement qui se déclenche lorsque cette méthode est terminée. Je veux résoudre une promesse, en utilisant cet événement comme rappel me sécurisant cette méthode a été achevée avec succès. Array.lenght sur promesse peut être X. Donc, j'ai besoin d'entendre x fois l'événement pour me garantir que toutes les méthodes ont terminé avec succès < - Ce n'est pas le problème, je vous dis juste que je savoir cela pourrait se produireAttendre un événement pour résoudre une promesse

événement:

tf2.on('craftingComplete', function(recipe, itemsGained){ 
    if(recipe == -1){ 
    console.log('CRAFT FAILED') 
    } 
    else{ 
     countOfCraft++; 
    console.log('Craft completed! Got a new Item #'+itemsGained); 
    } 
}) 

Promise:

const craftWepsByClass = function(array, heroClass){ 
     return new Promise(function (resolve, reject){ 

      if(array.length < 2){ 
       console.log('Done crafting weps of '+heroClass); 
       return resolve(); 
      } 
      else{ 
       for (var i = 0; i < array.length; i+=2) { 
        tf2.craft([array[i].id, array[i+1].id]); // <--- this is the module method witouth callback 
       } 
     return resolve(); // <---- I want resolve this, when all tf2.craft() has been completed. I need 'hear' event many times as array.length 
      } 

     }) 
} 
+0

Est-ce que 'tf2.craft()' retourne un 'Promise'? Notez qu'une «promesse» ne peut être résolue ou rejetée qu'une seule fois. – guest271314

+0

@ guest271314 Ne pas. tf2.craft() ne retourne rien; –

+0

'qui a une méthode sans callbacks.'bien' on' est un rappel .. :) – Keith

Répondre

0

Dans un premier temps permet promisify le craft:

function craft(elem){ 
//do whatever 
return Promise((resolve,reject) => 
    tf2.on('craftingComplete', (recipe,itemsGained) => 
    if(recipe !== -1){ 
    resolve(recipe, itemsGained); 
    }else{ 
    reject("unsuccessful"); 
    } 
    }) 
); 
} 

donc à des multiples d'artisanat puis, nous comparons nos promesses et tableau à utiliser Promise.all:

Promise.all(array.map(craft)) 
.then(_=>"all done!") 
+0

D'où viennent les mots «résoudre» et «rejeter»? Ils ne semblent pas être dans la portée. – Bergi

+0

@Bergi vous avez un jour de congé? résoudre et rejeter sont dans le rappel Promise .. – Keith

+1

@Keith La fonction exécuteur 'Promise' n'a pas été inclus au code à l'origine Answer – guest271314

-1

Je dois vérifier si l'événement 'craftingComplete' a tiré plusieurs fois que je l'appelle tf2.craft. N'importe pas d'ID posible ou si l'engin a échoué. Je besoin de savoir si tf2.craft a fini et pourquoi ne vérifie événement « craftingComplete »

Étant donné que nous savons i au sein de la boucle for sera incrémenté i += 2i est inférieur à .length de array, nous pouvons créer une variable égale à ce nombre avant la boucle for et comparer i au nombre dans les gestionnaire d'événements

const craftWepsByClass = function(array, heroClass) { 
    return new Promise(function(resolve, reject) { 

    var countCraft = 0; 
    var j = 0; 
    var n = 0; 
    for (; n < array.length; n += 2); 

    tf2.on('craftingComplete', function(recipe, itemsGained) { 
     if (recipe == -1) { 
     console.log('CRAFT FAILED') 
     } else { 
     countOfCraft++; 
     console.log('Craft completed! Got a new Item #' + itemsGained); 
     if (j === n) { 
      resolve(["complete", craftCount]) 
     } 
     } 
    }) 

    if (array.length < 2) { 
     console.log('Done crafting weps of ' + heroClass); 
     return resolve(); 
    } else { 
     try { 
     for (var i = 0; i < array.length; i += 2, j += 2) { 
      tf2.craft([array[i].id, array[i + 1].id]); 
     } 
     } catch (err) { 
     console.error("catch", err); 
     throw err 
     } 
    } 

    }) 
} 

craftWepsByClass(array, heroClass) 
.then(function(data) { 
    console.log(data[0], data[1]) 
}) 
.catch(function(err) { 
    console.error(".catch", err) 
}) 
+0

Je ne pense pas que vous vouliez ajouter un nouveau gestionnaire 'craftingComplete' chaque fois que' craftWepsByClass' est appelé. – Bergi

+0

@Bergi Probablement pas. 'craftWepsByClass()' ne serait appelé qu'une seule fois pour chaque nouvelle instance de 'tf2'. OP a maintenant plusieurs solutions possibles à choisir. – guest271314

+0

"*' craftWepsByClass() 'ne serait appelé qu'une seule fois pour chaque nouvelle instance de' tf2'. * "- Comment le savez-vous? Pourquoi pensez-vous même qu'il existe plusieurs instances de 'tf2'? – Bergi

0

Si les événements seront tirés dans le même un ordre s les appels craft() respectifs qui les ont amenés, vous pouvez utiliser une file d'attente:

var queue = []; // for the tf2 instance 
function getNextTf2Event() { 
    return new Promise(resolve => { 
    queue.push(resolve); 
    }); 
} 
tf2.on('craftingComplete', function(recipe, itemsGained) { 
    var resolve = queue.shift(); 
    if (recipe == -1) { 
    resolve(Promise.reject(new Error('CRAFT FAILED'))); 
    } else { 
    resolve(itemsGained); 
    } 
}); 

function craftWepsByClass(array, heroClass) { 
    var promises = []; 
    for (var i = 1; i < array.length; i += 2) { 
    promises.push(getNextTf2Event().then(itemsGained => { 
     console.log('Craft completed! Got a new Item #'+itemsGained); 
     // return itemsGained; 
    })); 
    tf2.craft([array[i-1].id, array[i].id]); 
    } 
    return Promise.all(promises).then(allItemsGained => { 
    console.log('Done crafting weps of '+heroClass); 
    return …; 
    }); 
} 

Si vous ne savez pas quoi que ce soit sur l'ordre des événements, et il peut y avoir plusieurs appels simultanés à craftWepsByClass, vous ne pouvez pas éviter compteur global (ie un lié à l'instance tf2). L'inconvénient est que, par exemple. dans deux appels qui se chevauchent, la promesse a ne sera pas résolue avant la fin de l'élaboration du second appel.

var waiting = []; // for the tf2 instance 
var runningCraftings = 0; 
tf2.on('craftingComplete', function(recipe, itemsGained) { 
    if (--runningCraftings == 0) { 
    for (var resolve of waiting) { 
     resolve(); 
    } 
    waiting.length = 0; 
    } 
    if (recipe == -1) { 
    console.log('CRAFT FAILED') 
    } else { 
    console.log('Craft completed! Got a new Item #'+itemsGained); 
    } 
}); 

function craftWepsByClass(array, heroClass) { 
    for (var i = 1; i < array.length; i += 2) { 
    runningCraftings++; 
    tf2.craft([array[i-1].id, array[i].id]); 
    } 
    return (runningCraftings == 0 
    ? Promise.resolve() 
    : new Promise(resolve => { 
     waiting.push(resolve); 
     }) 
).then(() => { 
    console.log('Done crafting weps of '+heroClass); 
    }); 
} 

Bien sûr, dans les deux solutions, vous devez être certain à 100% que chaque appel à craft() cause exactement un événement.

+0

Bonne prise, il n'y en avait pas censé être. – Bergi