[英]Wait an event to resolve a promise
I am using a node.js module that has a method without callbacks.我正在使用一个 node.js 模块,它有一个没有回调的方法。 Instead of it, has an event that fires when that method has finished.
取而代之的是,有一个在该方法完成时触发的事件。 I want resolve a promise, using that event as callback securing me that method has been completed succesfully.
我想解决一个承诺,使用该事件作为回调确保该方法已成功完成。
array.lenght on promise can be X. So, I need 'hear' X times the event to secure me that all methods has completed succesfully <-- This is not the problem, I am just telling you that I know this could happen array.lenght on promise 可以是 X。所以,我需要“听到”X 次事件来确保所有方法都成功完成<--这不是问题,我只是告诉你我知道这可能发生
Event :事件 :
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
}
})
}
At first lets promisify the crafting:首先让我们承诺制作:
function craft(elem){
//do whatever
return Promise((resolve,reject) =>
tf2.on('craftingComplete', (recipe,itemsGained) =>
if( recipe !== -1 ){
resolve(recipe, itemsGained);
}else{
reject("unsuccessful");
}
})
);
}
So to craft multiples then, we map our array to promises and use Promise.all:因此,为了制作倍数,我们将数组映射到 promises 并使用 Promise.all:
Promise.all( array.map( craft ) )
.then(_=>"all done!")
If the events will be fired in the same order as the respective craft()
calls that caused them, you can use a queue:如果事件的触发顺序与引起它们的各个
craft()
调用的顺序相同,则可以使用队列:
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 …;
});
}
If you don't know anything about the order of the events, and there can be multiple concurrent calls to craftWepsByClass
, you cannot avoid a global counter (ie one linked to the tf2
instance).如果您对事件的顺序一无所知,并且可能有多个对
craftWepsByClass
并发调用,则无法避免全局计数器(即链接到tf2
实例的计数器)。 The downside is that eg in two overlapping calls a = craftWepsByClass(…), b = craftWepsByClass()
the a
promise won't be resolved until all crafting of the second call is completed.缺点是,例如在两个重叠的调用
a = craftWepsByClass(…), b = craftWepsByClass()
,在第二次调用的所有制作完成之前, a
承诺不会被解析。
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);
});
}
Of course in both solutions you must be 100% certain that each call to craft()
causes exactly one event.当然,在这两种解决方案中,您必须 100% 确定每次调用
craft()
都会导致一个事件。
You can look at the event-as-promise
package.您可以查看
event-as-promise
包。 It convert events into Promise continuously until you are done with all the event processing.它不断将事件转换为 Promise,直到您完成所有事件处理。
When combined with async
/ await
, you can write for-loop or while-loop easily with events.与
async
/ await
结合使用时,您可以使用事件轻松编写 for-loop 或 while-loop。 For example, we want to process data
event until it return null
.例如,我们要处理
data
事件,直到它返回null
。
const eventAsPromise = new EventAsPromise();
emitter.on('data', eventAsPromise.eventListener);
let done;
while (!done) {
const result = await eventAsPromise.upcoming();
// Some code to process the event result
process(result);
// Mark done when no more results
done = !result;
}
emitter.removeListener('data', eventAsPromise.eventListener);
If you are proficient with generator function, it may looks a bit simpler with this.如果您精通生成器功能,那么它可能看起来更简单一些。
const eventAsPromise = new EventAsPromise();
emitter.on('data', eventAsPromise.eventListener);
for (let promise of eventAsPromise) {
const result = await promise;
// Some code to process the event result
process(result);
// Stop when no more results
if (!result) {
break;
}
}
emitter.removeListener('data', eventAsPromise.eventListener);
I need check if event 'craftingComplete' has fired many times as I call tf2.craft.
当我调用 tf2.craft 时,我需要检查事件 'craftingComplete' 是否已多次触发。 Doesnt matters any posible ID or if craft has failed.
任何可能的 ID 或工艺是否失败都无关紧要。 I need to know if tf2.craft has finished and only why is checking 'craftingComplete' event
我需要知道 tf2.craft 是否已完成,以及为什么要检查“craftingComplete”事件
Given that we know i
within for
loop will be incremented i += 2
where i
is less than .length
of array
, we can create a variable equal to that number before the for
loop and compare i
to the number within event handler由于我们知道
i
内for
循环将递增i += 2
,其中i
小于.length
的array
,我们可以创建一个变量等于该数字前的for
循环和比较i
的号码事件处理程序中
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)
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.