Home > front end >  Can't get rid of a global variable (Need to make it non-global)
Can't get rid of a global variable (Need to make it non-global)

Time:06-27

I'm working on a web app that shows the total duration of a playlist so we're dealing with YouTube API here. So here, I want to know how should I get rid of the global variable newPageToken in this case and still be able to use it in the third function on this snippet.

let newPageToken = null;

// Next page for more results (Max 50 per page)
function getNextTokenURL() {
    console.log(newPageToken);
    return newPageToken
        ? `${playlistItemsURL}&playlistId=${extractedPlaylistIDId}&pageToken=${newPageToken}&key=${API_KEY}`
        : `${playlistItemsURL}&playlistId=${extractedPlaylistIDId}&key=${API_KEY}`;
}



async function getVideoIdsForPageToken() {
    try {
        const { data } = await axios.get(getNextTokenURL());
        const nextPageToken = data.nextPageToken;
        const videoIds = data.items.map((video) => {
            return video.contentDetails.videoId;
        });
        return { videoIds, nextPageToken };
    } catch (e) {
        if (e.response) {
            const { code, message } = e.response.data.error;
            throw new Error(`StatusCode ${code}. Reason: ${message}`);
            console.log("Errow while fetching videos list.");
        } else {
            throw new Error(e.message);
        }
    }
}



// Navigates between the videos per page and adds them (Maximum 50)
async function getPlaylistData() {
    try {
        const { videoIds, nextPageToken } = await getVideoIdsForPageToken();
        let pageToken = nextPageToken;
        newPageToken = pageToken;
        const returnedVideoIds = [];
        returnedVideoIds.push(getDetailsForVideoIds(videoIds));
        const videoGroups = await Promise.all(returnedVideoIds);



        for (const group of videoGroups) {
            for (const video of group) {
                finalTotalDuration  = returnedToSeconds(video.contentDetails.duration);
            }
        }

        // console.log(videoIds);
        if (nextPageToken) {
            await getPlaylistData();
        }
    } catch (e) {
        throw new Error(e.message);
        console.log("Error while navigating between video pages.");
    }
}```

CodePudding user response:

Assumptions

  1. finalTotalDuration is also a global variable declared somewhere (Not a good idea)
  2. You call getPlaylistData for multiple playlist for multiple users

Solution

You need to ensure the getPlaylistData is standalone and returns the finalTotalDuration as a return value (not set a global one)

To make it standalone it has to be iterative in nature. It should be a recursive function which does the following

async function getPlaylistTotalDuration(newPageToken) {

    // Step 1: Create the required query URL based on the newPageToken parameter
    // Step 2: Start a local duration counter
    // Step 3: Get the video details based on the URL created in Step 1
    // Step 4: Get the durations in seconds and add it to the local duration counter created in Step 2
    // Step 5: Check if the return of Step 3 has a nextPageToken, if so do a recursive call to self with the new token
    // Step 6: Return the final value, which will propogate back in a recursive function

}

You can simply call the function like

let finalTotalDuration = getPlaylistTotalDuration(null); // or getPlaylistTotalDuration();

for example the below getPlaylistTotalDuration is a replacement to your getPlaylistData method


async function getVideoIdsForPageToken(url) {
    try {
        const { data } = await axios.get(url);
        const nextPageToken = data.nextPageToken;
        const videoIds = data.items.map((video) => {
            return video.contentDetails.videoId;
        });
        return { videoIds, nextPageToken };
    } catch (e) {
        if (e.response) {
            const { code, message } = e.response.data.error;
            throw new Error(`StatusCode ${code}. Reason: ${message}`);
            console.log("Errow while fetching videos list.");
        } else {
            throw new Error(e.message);
        }
    }
}


async function getPlaylistTotalDuration(newPageToken) {
    try {        
        // Step 1: Create the required query URL based on the newPageToken parameter
        let url = newPageToken
        ? `${playlistItemsURL}&playlistId=${extractedPlaylistIDId}&pageToken=${newPageToken}&key=${API_KEY}`
        : `${playlistItemsURL}&playlistId=${extractedPlaylistIDId}&key=${API_KEY}`;

        // Step 2: Start a local duration counter
        let totalDuration = 0;

        // Step 3: Get the video details based on the URL created in Step 1
        const { videoIds, nextPageToken } = await getVideoIdsForPageToken(url);
        const returnedVideoIds = [];
        returnedVideoIds.push(getDetailsForVideoIds(videoIds));
        const videoGroups = await Promise.all(returnedVideoIds);

        for (const group of videoGroups) {
            for (const video of group) {
                // Step 4: Get the durations in seconds and add it to the local duration counter created in Step 2
                totalDuration  = returnedToSeconds(video.contentDetails.duration);
            }
        }

        // Step 5: Check if the return of Step 3 has a nextPageToken, if so do a recursive call to self with the new token
        if (nextPageToken) {
            totalDuration  = await getPlaylistTotalDuration(nextPageToken);
        }

        // Step 6: Return the final value, which will propogate back in a recursive function
        return totalDuration;
    } catch (e) {
        throw new Error(e.message);
        console.log("Error while navigating between video pages.");
    }
}

Note: I have not actually ran the above code, but hopefully you get an idea of what needs to be done.

  • Related