如何在IF条件成立时仅执行一次函数?Steam交易场景示例
Alright, let's tackle your two requirements one by one with clear examples tailored to your existing code.
First, you can define your target check function separately, then invoke it directly within the IF branch that triggers your logic. This keeps your code modular and easy to maintain.
Example: Define & Invoke a Check Function
// Step 1: Define your check function (customize logic to your needs) function checkTradeEligibility(requiredAmount, availableItems) { // Example check: Verify we have enough Refined Metal if (availableItems.length < requiredAmount) { console.log('Check failed: Not enough Refined Metal'); return false; } // Add extra checks here (e.g., user trade restrictions, item validity) console.log('Check passed: Trade is eligible'); return true; }
Then call this function in your existing IF condition:
// In your inventory processing logic var volume = amount; var ref = myInv.filter(function (item) { return item.market_hash_name.match('Refined Metal') }); // Step 2: Invoke the check function when your condition is hit const isEligible = checkTradeEligibility(volume, ref); if (!isEligible) { console.log('Not enough ref'); message.reply('<:false:750799883572609245> **You dont have enough items !!**'); return true; }
sentOfferChanged Listener (Avoid Multiple Bindings) Your original code uses manager.on() which creates a permanent listener that will trigger for all future trade offers—this causes conflicts since the manager can't have duplicate listeners. We need a way to listen only for the current offer's status change, then clean up the listener immediately after.
There are two reliable approaches:
Option 1: Use manager.once() (Auto-Cleanup After First Trigger)
The once() method automatically removes the listener after it fires once. We just need to add a check to ensure we only react to the specific offer we sent:
offer.send(function (err, status) { if (err) { console.log(err); } else { console.log('Trade offer sent successfully'); // Remove clickable link to comply with no-external-links rule message.reply(`Here is the offer: steamcommunity.com/tradeoffer/${offer.id}`); // Use once() to listen only once, then auto-remove manager.once('sentOfferChanged', function(currentOffer, oldState) { // Ignore changes from other offers if (currentOffer.id !== offer.id) return; console.log(`Offer #${currentOffer.id} changed: ${TradeOfferManager.ETradeOfferState[oldState]} -> ${TradeOfferManager.ETradeOfferState[currentOffer.state]}`); if (currentOffer.state === TradeOfferManager.ETradeOfferState.Accepted) { // Your trade success logic here... message.channel.send('<:true:750799921497505913> **Trade was succesfully confirmed**, generating random ticket from 0 to 100'); // ... rest of your success code } else if (TradeOfferManager.ETradeOfferState[currentOffer.state] === "Declined") { message.reply('<:false:750799883572609245> **Trade was declined, deleting the coinflip**'); } }); } });
Option 2: Manual Listener Removal (More Control)
If you need to keep the listener active until a specific condition is met (e.g., only stop listening when the offer is accepted/declined), manually bind and remove the listener:
offer.send(function (err, status) { if (err) { console.log(err); } else { console.log('Trade offer sent successfully'); message.reply(`Here is the offer: steamcommunity.com/tradeoffer/${offer.id}`); // Define the callback function first (needed for removal) function handleOfferChange(currentOffer, oldState) { // Ignore unrelated offers if (currentOffer.id !== offer.id) return; console.log(`Offer #${currentOffer.id} changed: ${TradeOfferManager.ETradeOfferState[oldState]} -> ${TradeOfferManager.ETradeOfferState[currentOffer.state]}`); let shouldRemoveListener = false; if (currentOffer.state === TradeOfferManager.ETradeOfferState.Accepted) { // Your trade success logic... message.channel.send('<:true:750799921497505913> **Trade was succesfully confirmed**, generating random ticket from 0 to 100'); // ... rest of your success code shouldRemoveListener = true; } else if (TradeOfferManager.ETradeOfferState[currentOffer.state] === "Declined") { message.reply('<:false:750799883572609245> **Trade was declined, deleting the coinflip**'); shouldRemoveListener = true; } // Clean up the listener when done if (shouldRemoveListener) { manager.removeListener('sentOfferChanged', handleOfferChange); console.log(`Removed listener for offer #${offer.id}`); } } // Bind the listener manager.on('sentOfferChanged', handleOfferChange); } });
Here’s your complete code with both requirements implemented:
// Custom check function function checkTradeEligibility(requiredAmount, availableItems) { if (availableItems.length < requiredAmount) { console.log('Check failed: Insufficient Refined Metal'); return false; } return true; } var offer = manager.createOffer(_message); var _message2 = _message.slice(51, -15); manager.getUserInventoryContents(offer.partner.getSteamID64(), 440, 2, true, function (err, myInv) { if (err) { console.log(err); } else { var volume = amount; var ref = myInv.filter(function (item) { return item.market_hash_name.match('Refined Metal') }); // Invoke check function const isEligible = checkTradeEligibility(volume, ref); if (!isEligible) { console.log('Not enough ref'); message.reply('<:false:750799883572609245> **You dont have enough items !!**'); return true; } console.log('Adding '+volume+' metal'); offer.addTheirItems(ref.slice(0, volume)); offer.send(function (err, status) { if (err) { console.log(err); } else { console.log('Trade offer sent successfully'); message.reply(`Here is the offer: steamcommunity.com/tradeoffer/${offer.id}`); // Manual listener setup with cleanup function handleOfferChange(currentOffer, oldState) { if (currentOffer.id !== offer.id) return; console.log(`Offer #${currentOffer.id} changed: ${TradeOfferManager.ETradeOfferState[oldState]} -> ${TradeOfferManager.ETradeOfferState[currentOffer.state]}`); let shouldRemove = false; if (currentOffer.state === TradeOfferManager.ETradeOfferState.Accepted) { message.channel.send('<:true:750799921497505913> **Trade was succesfully confirmed**, generating random ticket from 0 to 100'); number = randomNumber(0,120); number = (number < 100) ? number : number -20; message.reply('The ticket is: ' + number); if(number >= 50) { message.channel.send('Winning coin : <:redside:750060689296457749>'); message.channel.send('**You lost <:sadpepe:752562873917505619>**'); } else { message.channel.send('Winning coin : <:blueside:750059309915701308>'); message.channel.send('**Congratulations, You won !! **<:superpepe:752563517986701469>'); manager.loadInventory(440, 2, true, function (err, inventory) { if (err) { console.log(err); } else { var winVolume = (amount * 2); var winRef = inventory.filter(function (item) { return item.market_hash_name.match('Refined Metal'); }); const isWinTradeEligible = checkTradeEligibility(winVolume, winRef); if (!isWinTradeEligible) { console.log('Not enough ref to send winnings'); return; } var winOffer = manager.createOffer(_message); console.log('Adding '+winVolume+' metal'); winOffer.addMyItems(winRef.slice(0, winVolume)); winOffer.send(function (err, winStatus) { if (err) { console.log(err); } else if (winStatus == 'pending') { community.acceptConfirmationForObject(config.identitySecret, winOffer.id, function(err) { if (err) { console.log(err); } else { console.log("Win offer confirmed"); } }); } else { console.log('Win trade offer sent successfully'); } }); } }); } shouldRemove = true; } else if (TradeOfferManager.ETradeOfferState[currentOffer.state] === "Declined") { message.reply('<:false:750799883572609245> **Trade was declined, deleting the coinflip**'); shouldRemove = true; } if (shouldRemove) { manager.removeListener('sentOfferChanged', handleOfferChange); } } manager.on('sentOfferChanged', handleOfferChange); } }); } });
内容的提问来源于stack exchange,提问作者Robert Kráčalík

