2

I want to know how to avoid the pyramid of doom of this code:

Original code

var PlayerService = {
    getPlayerTeamId: function(playerId, callback) {
        $.ajax({
            url: "/player/" + playerId + "/team",
            success: function(team) {
                callback(team.id)
            }
        });
    },
    getPlayers: function(teamId, callback) {
        $.ajax({
            url: "/team/" + teamId + "/player",
            success: callback
        });
    }
};

var PlayerDetailsController = {
    playerId: 8,
    showTeammatesClick: function() {
        PlayerService.getPlayerTeamId(this.playerId, function(teamId) {
            PlayerService.getPlayers(teamId, function(playerList) {
                // Render playerList
            });
        });
    }
};

and this is my version with async/await to avoid sol that pyramid: My version

var PlayerService = {
    getPlayerTeamId: async function(playerId, callback) {
        return await $.ajax({
                   url: "/player/" + playerId + "/team",
                   success: function(team) {
                       callback(team.id)
                   }
               });
    },
    getPlayers: async function(teamId, callback) {
        return await $.ajax({
                   url: "/team/" + teamId + "/player",
                   success: callback
               });
    }
};

var PlayerDetailsController = {
    playerId: 8,
    showTeammatesClick: function() {
        PlayerService.getPlayerTeamId(this.playerId, function(teamId) {
            PlayerService.getPlayers(teamId, function(playerList) {
                // Render playerList
            });
        });
    }
};

Is it OK ? or how can I use this async/await correctly? I'm trying that "getPlayerTeamId" and "getPlayers" should not expect the callback parameter, and avoid callback in any way.

any advise ? Thanks and have a good day :D

coudy.one
  • 1,382
  • 12
  • 24
Deivbid
  • 393
  • 2
  • 6
  • 15
  • There are a few questions about this on the site, including [Node.js, the pyramid of doom (even with async), can you write it better?](https://stackoverflow.com/q/25575837) and [avoid multiple returns looped in javascript - async / await to solve callback pyramid or callback hell,](https://stackoverflow.com/q/46167078). Do either of those answer your question? – Heretic Monkey Sep 14 '18 at 12:51

2 Answers2

5

The pyramid of doom is not solved from placing async/await somewhere, but from returning and chaining promises instead of accepting callbacks. Notice that your service methods don't even need to be async when they just can return a promise - in any case don't use return await:

const PlayerService = {
    getPlayerTeamId(playerId ) {
//                          ^ no callback
        return $.ajax({
//      ^^^^^^ the promise
            url: "/player/" + playerId + "/team"
        }).then(team => team.id);
    },
    // same here
    getPlayers(teamId) {
        return $.ajax({
            url: "/team/" + teamId + "/player"
        });
    }
};

Now that the promisification is done, we can start using promise .then() or await syntax instead of nesting callbacks when calling these methods:

const PlayerDetailsController = {
    playerId: 8,
    async showTeammatesClick() {
        const teamId = await PlayerService.getPlayerTeamId(this.playerId);
        const playerList = await PlayerService.getPlayers(teamId);
        … // Render playerList
    }
};
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

I assume that if you are using async/await, your codebase is in ES6.

So you can actually just use Fetch API to replace the $.ajax({...}) syntax:

var PlayerService = {
    getPlayerTeamId: function(playerId) {
        return fetch(`/player/${playerId}/team`);
    },
    getPlayers: function(teamId) {
        return fetch(`/team/${teamId}/player`);
    }
};

var PlayerDetailsController = {
    playerId: 8,
    showTeammatesClick: async function() {
        const teamId = await PlayerService.getPlayerTeamId(this.playerId);
        const playerList = await PlayerService.getPlayers(teamId);

        /* Render playerList here */
    }
};

The point of using async/await or Promises is to avoid callbacks, which solves the "pyramid of doom".

So when building your PlayerService functions, you can skip the callback parameter altogether.

Alternatively, you can also just use plain Promise syntax:

var PlayerService = {
    getPlayerTeamId: function(playerId) {
        return fetch(`/player/${playerId}/team`);
    },
    getPlayers: function(teamId) {
        return fetch(`/team/${teamId}/player`);
    }
};

var PlayerDetailsController = {
    playerId: 8,
    showTeammatesClick: function() {
        PlayerService.getPlayerTeamId(this.playerId)
          .then(PlayerService.getPlayers)
          .then(playerList => {
              /* Render playerList here */
          });
    }
};
yqlim
  • 6,898
  • 3
  • 19
  • 43