Promise Advanced

  1. Promise.all() and Promise.allSettled()

    Promise.all and Promise.allSettled are both methods for handling multiple concurrent Promises, but they differ in how they handle successful and failed Promises.


  2. Promise.all

    Promise.all accepts an array of Promise as parameters.

    • When all Promises are resolved, Promise.all is also resolved, and the return value is an array containing the results of all successful Promises.

    • If any Promise fails (rejected), Promise.all will also immediately fail (rejected), and the return value is the reason for the first failed Promise.

      This means that if you use Promise.all, if one Promise fails, the entire Promise.all will fail immediately before all Promises have completed. Therefore, Promise.all is more suitable for scenarios where all Promises need to succeed.

    1
    2
    3
    4
    5
    6
    7
    javascriptCopy codePromise.all([promise1, promise2, promise3])
    .then((results) => {
    // All promises fulfilled successfully
    })
    .catch((error) => {
    // At least one promise was rejected
    });

  3. Promise.allSettled

    Promise.allSettled also accepts an array of Promise as parameters.

    • Promise.allSettled will wait for all Promises to complete, regardless of whether each Promise succeeds or fails.
    • Promise.allSettled succeeds (resolved) when all Promises are completed (regardless of success or failure), and the return value is an array containing the status of all Promise (success or failure). Each element in the array is an object that contains a status property (with a value of "fulfilled" or "rejected") and a value (the result on success) or reason (on failure time reason) attribute.
    • This means that if you use Promise.allSettled, even if one or more Promises fail, the entire Promise.allSettled will still succeed and return the final status of all Promises. Therefore, Promise.allSettled is more suitable for scenarios where you need to know the final status of all Promises, not just the success status.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    const promise1 = Promise.resolve(3);
    const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'Error'));
    const promise3 = Promise.resolve(5);

    Promise.all([promise1, promise2, promise3])
    .then(console.log)
    .catch(console.error); // Output: Error (because promise2 was rejected)

    Promise.allSettled([promise1, promise2, promise3])
    .then(console.log)
    .catch(console.error);
    // Output: [
    // { status: "fulfilled", value: 3 },
    // { status: "rejected", reason: "Error"


  4. Example: Music Player

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121

    interface ArtistResults {
    status: "fulfilled" | "rejected";
    value: IBanner;
    }

    interface AlbumListResults {
    status: "fulfilled" | "rejected";
    value: IAlbumList;
    }

    function getRandomInt() {
    return Math.floor(Math.random() * 10);
    }

    async function getArtist(areaCode: AreaCode) {
    const randomInteger = Math.floor(Math.random() * 100000) + 1;
    const artistRes = await fetch(
    `${
    process.env.NEXT_PUBLIC_SERVER_ADDRESS
    }/artist/list?area=${areaCode}&limit=1&offset=${getRandomInt()}&timestamp=${
    Date.now() - randomInteger
    }`
    );
    const artistArray = await artistRes.json();
    const artist = artistArray.artists[0];

    const artistSongRes = await fetch(
    `${process.env.NEXT_PUBLIC_SERVER_ADDRESS}/artists?id=${
    artist.id
    }&limit=6&order=time&timestamp=${Date.now() - randomInteger}`
    );
    const artistDetails = await artistSongRes.json();
    const artistSongsDetails = artistDetails.hotSongs.slice(0, 6) as IAlbumSong[];
    const artistSongs = artistSongsDetails.map((song) => {
    return {
    name: song.name,
    id: song.id,
    image: song.al.picUrl,
    };
    });

    const colorRes = await fetch(
    `${
    process.env.NEXT_PUBLIC_CLIENT_ADDRESS
    }/api/colorExtract?imageUrl=${convertToHttps(artist.picUrl)}`
    );
    const color = await colorRes.json();

    const banner: IBanner = {
    artistId: artist.id,
    artistName: artist.name,
    artistCover: convertToHttps(artist.picUrl) as string,
    artistAreaCode: areaCode,
    artistAlias: artist.alias,
    bgColor: color.dominantColor,
    artistSongs: artistSongs,
    };
    return banner;
    }

    export async function fetchArtistsInfo(areas: AreaCode[]) {
    try {
    const promises = areas.map((area: AreaCode) => getArtist(area));
    const results = await Promise.allSettled(promises);
    const filteredResults = results.filter(
    (result) => result.status === "fulfilled"
    ) as ArtistResults[];
    const resultAlbums = filteredResults.map((results: ArtistResults) => {
    return results.value;
    });
    return resultAlbums;
    } catch (error) {
    console.error("Error fetching data:", error);
    throw error;
    }
    }

    async function getAlbumLists(area: AlbumArea) {
    const albumRes = await fetch(
    `${process.env.NEXT_PUBLIC_SERVER_ADDRESS}/album/list/style?area=${area}&limit=13`
    );
    const rawAlbumLists = await albumRes.json();
    const albumLists = {
    ...rawAlbumLists,
    title: albumAreaMapper(area),
    path: `album/list/style?area=${area}&`,
    };
    return albumLists;
    }

    export async function fetchAlbumListInfo(albumAreas: AlbumArea[]) {
    try {
    const promises = albumAreas.map((albumArea: AlbumArea) =>
    getAlbumLists(albumArea)
    );
    const results = await Promise.allSettled(promises);
    const filteredResults = results.filter(
    (result) => result.status === "fulfilled"
    ) as AlbumListResults[];

    const resultAlbumLists = filteredResults.map(
    (results: AlbumListResults) => {
    return results.value;
    }
    );
    return resultAlbumLists;
    } catch (error) {
    console.error("Error in fetching area album lists data:", error);
    throw error;
    }
    }

    export async function getPlaylistList(playListType: "/highquality" | "") {
    const topPlaylistListResponse = await fetch(
    `${process.env.NEXT_PUBLIC_SERVER_ADDRESS}/top/playlist${playListType}?limit=13`
    );
    const rawTopLists = await topPlaylistListResponse.json();
    const topPlaylistList = await playlistsGroupTranslator(rawTopLists);
    return { ...topPlaylistList, path: `top/playlist${playListType}?` };
    }

Share