[英]Wait an event to resolve a promise
我正在使用一個 node.js 模塊,它有一個沒有回調的方法。 取而代之的是,有一個在該方法完成時觸發的事件。 我想解決一個承諾,使用該事件作為回調確保該方法已成功完成。
array.lenght on promise 可以是 X。所以,我需要“聽到”X 次事件來確保所有方法都成功完成<--這不是問題,我只是告訴你我知道這可能發生
事件 :
tf2.on('craftingComplete', function(recipe, itemsGained){
if(recipe == -1){
console.log('CRAFT FAILED')
}
else{
countOfCraft++;
console.log('Craft completed! Got a new Item #'+itemsGained);
}
})
承諾:
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
}
})
}
首先讓我們承諾制作:
function craft(elem){
//do whatever
return Promise((resolve,reject) =>
tf2.on('craftingComplete', (recipe,itemsGained) =>
if( recipe !== -1 ){
resolve(recipe, itemsGained);
}else{
reject("unsuccessful");
}
})
);
}
因此,為了制作倍數,我們將數組映射到 promises 並使用 Promise.all:
Promise.all( array.map( craft ) )
.then(_=>"all done!")
如果事件的觸發順序與引起它們的各個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 …;
});
}
如果您對事件的順序一無所知,並且可能有多個對craftWepsByClass
並發調用,則無法避免全局計數器(即鏈接到tf2
實例的計數器)。 缺點是,例如在兩個重疊的調用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);
});
}
當然,在這兩種解決方案中,您必須 100% 確定每次調用craft()
都會導致一個事件。
您可以查看event-as-promise
包。 它不斷將事件轉換為 Promise,直到您完成所有事件處理。
與async
/ await
結合使用時,您可以使用事件輕松編寫 for-loop 或 while-loop。 例如,我們要處理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);
如果您精通生成器功能,那么它可能看起來更簡單一些。
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);
當我調用 tf2.craft 時,我需要檢查事件 'craftingComplete' 是否已多次觸發。 任何可能的 ID 或工藝是否失敗都無關緊要。 我需要知道 tf2.craft 是否已完成,以及為什么要檢查“craftingComplete”事件
由於我們知道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.