Generating a performance report for clans in Clash Royale The following code generates a report showing performance of clan members in a game called Clash Royale.
Everything is pretty self-explanatory, we are working with a lot of https requests, arrays and sorting.
const https = require(&quot;https&quot;);
const clanTag = &quot;L2P8GRJR&quot;;
const token = &quot;TOKEN_HERE&quot;

let rawData = '';
let topDonators = [];
let worstDonators = [];
let bestPlayers = [];
let counter = 0;
const mergeByProperty = (target, source, prop) =&gt; {
    source.forEach(sourceElement =&gt; {
        let targetElement = target.find(targetElement =&gt; {
            return sourceElement[prop] === targetElement[prop];
        })
        targetElement ? Object.assign(targetElement, sourceElement) : null;
    })
}

const finalise = () =&gt; {
    if (counter !== 2) return;

    let result = `CR Clan Youtube Weekly Report
°•°•°•°•°•°•°•°•°•°•°•°•

— Top Donators ——
~~~~~~~~~~~~~~~~~~
${topDonators.map((x, i) =&gt; `${i + 1}. ${x.name} - ${x.donations}`).join('\n')}
--------------------

— Back Donators ( &lt; 100 ) ——
~~~~~~~~~~~~~~~~~~~
${worstDonators.map((x, i) =&gt; `${50 - i}. ${x.name} - ${x.donations}`).join('\n')}
--------------------

— Net Best Players ——
(Donations × Fame earned ÷ (100 × 1000))
===================
${bestPlayers.map((x, i) =&gt; `${i + 1}. ${x.name} - ${x.netScore}`).join('\n')}
===================

{ ${bestPlayers[0].name} } is the player of the week, congrats!

Data automatically fetched and compiled at ${new Date().toUTCString()}.

Earn fame in river race and donate cards to improve your net score which will be published on Sunday. Player of The Week will be chosen based on net score. Better net score may also result in promotion.

CR may not show full report to some players, hence this report is also published to the Discord server (link in the description).`
    console.log(result)
}

https.get(`https://proxy.royaleapi.dev/v1/clans/%23${clanTag}/members`, {
    headers: {
        authorization: token
    }
}, (res) =&gt; {
    res.on(&quot;data&quot;, (data) =&gt; {
        rawData += data
    })
    res.on(&quot;end&quot;, () =&gt; {
        rawData = JSON.parse(rawData).items

        topDonators = [...rawData].sort((a, b) =&gt; b.donations - a.donations).slice(0, 10)

        rawData.forEach(elm =&gt; {
            if (elm.donations &lt; 100) worstDonators.push(elm)
        })
        worstDonators.sort((a, b) =&gt; a.donations - b.donations)
        counter++;
        finalise()
    })
})

https.get(`https://proxy.royaleapi.dev/v1/clans/%23${clanTag}/currentriverrace`, {
    headers: {
        authorization: token
    }
}, res =&gt; {
    let warData = [];
    res.on(&quot;data&quot;, data =&gt; {
        warData += data
    })

    res.on(&quot;end&quot;, () =&gt; {
        warData = JSON.parse(warData).clan.participants;
        mergeByProperty(rawData, warData, &quot;tag&quot;)

        bestPlayers = [...rawData].map(elm =&gt; {elm.netScore = elm.fame * elm.donations / 100000; return elm;}).sort((a,b) =&gt; b.netScore - a.netScore).slice(0, 10)
        counter++;
        finalise()
    })
})

A proxy is being used but just know that that's a necessity.
Performance is the main point here but I would love review on any and every point.
Cool project!
Good work so far.
Clean code is important and that's one of the things I struggle with. A lot.
From your code, I can see that you would benefit a lot from that too.
const token = &quot;TOKEN_HERE&quot;;

Tokens and sensitive information you should try to store in .env files. Especially if your code might be accessible on github or similar sites.
const mergeByProperty...

This function seems too complicated for what you want to do. I really don't think you need it at all.
Same for this:
const finalise...

Try to extract logic into functions, especially if you need to use it in other places.
Try to identify repeating code, if you see that, then you might be able to create a function for it.
Do not repeat yourself. Code you repeat is hard to maintain because if you make a small change you need to make that change everywhere.
Naming your functions and variables is equally important and it's harder than it seems.
This is what I would do differently (and even this can be improved a lot):
const baseUrl = 'https://proxy.royaleapi.dev/v1/clans';
const clanUrl =  `${baseUrl}/#${clanTag}/`;
const requestOptions = {
    headers: {
        authorization: token
        }
    }

// wrap your requests into a promise
const GET = (url, options = {}) =&gt; {
    return new Promise((resolve, reject) =&gt; {
        const request = https.get(url, options, (response) =&gt; {
            if (response.statusCode &lt; 200 || response.statusCode &gt; 299) {
                reject(new Error(response.statusCode));
            }
            let data = '';
            response.on('data', (chunk) =&gt; data += chunk);
            response.on('end', () =&gt; resolve(JSON.parse(data)));
        });
        request.on('error', (err) =&gt; reject(err))
    })
};

// do all the data manipulation inside these helper functions
// this transforms the data you get from the server into the format
// you want

const getMembers = (members) =&gt; {
    const donors = {
        top: [...members].sort((a, b) =&gt; b.donations - a.donations).slice(0, 10),
        worst: [...members].filter(x =&gt; x.donations &lt; 100).sort((a, b) =&gt; a.donations - b.donations)
    }
    return donors;
}

// transform the data from server into the format you want

const getCurrentRiverRace= (clanParticipants) =&gt; {
    const clan = {
        participants: clanParticipants,
        bestPlayers: [...clanParticipants].map(x =&gt; { 
            return {
                ...x,
                netScore: x.fame * x.donations / 100000
            };
        }).sort((a,b) =&gt; b.netScore - a.netScore).slice(0, 10)
    }
    return clan;
}

// this one makes both requests to the server at the same time
// Notice the async. Since your requests return promises, this is how you
// handle the promises

const requests = async () =&gt; {
    const membersCall = GET(`${clanUrl}/members`, requestOptions);
    const riverRaceCall = GET(`${clanUrl}/currentriverrace`, requestOptions);
    const [members, riverRace] = await Promise.all([membersCall, riverRaceCall]);
    
    return {
        members: getMembers(members),
        riverRace: getCurrentRiverRace(riverRace)
    }
}

// here you just 'finalise' or output whatever you want
// you should handle the errors so maybe wrap it in a try/catch.

const output = async () =&gt; {
    try {
        //
        const r = await requests();
        const stats = `
        CR Clan Youtube Weekly Report
        °•°•°•°•°•°•°•°•°•°•°•°•

        — Top Donators ——
        ${stats.members.top}
        ....
        `;

        console.log(stats);
        return stats;
   } catch (err) {
       // here you handle the error in case the promise rejects
       // (returns error)
       // console.log is NOT error handling but it gives you an idea

       console.log(err);
   }
}

Try to puzzle it together. I'm not sure if it's 100% functional but it should be pretty close. Consider it a homework :)