1

Here I use a global variable, usergb, because at the "then" block where I get the cart, I have no more access to the user. How can I pass the user with the cart, instead of having to create a global usergb ?

var usergb;
sequelize
  .sync()
  .then(result => {
    return User.findByPk(1);
  })
  .then(user => {
    if (!user) {
      return User.create({ name: 'Max', email: 'test@test.com' });
    }
    return user;
  })
  .then(user => {
    usergb = user;
    return user.getCart();
  })
  .then(cart => {   // here I lost the reference to user
    if (!cart) {
      return usergb.createCart();
    }
    return cart
  })
  .then(cart => {
    app.listen(3000);
  })
  .catch(err => {
    console.log(err);
  });
trogne
  • 3,402
  • 3
  • 33
  • 50

2 Answers2

3

Nest the promise in which you need to reference user.

sequelize
  .sync()
  .then(result => {
    return User.findByPk(1);
  })
  .then(user => {
    if (!user) {
      return User.create({ name: "Max", email: "test@test.com" });
    }

    return user;
  })
  .then(user => {
    return (
      user
        .getCart()
        // Nest the next promise here
        .then(cart => {
          if (!cart) {
            return usergb.createCart();
          }

          return cart;
        })
    );
  })
  .then(cart => {
    app.listen(3000);
  })
  .catch(err => {
    console.log(err);
  });
Umair Sarfraz
  • 5,284
  • 4
  • 22
  • 38
0

Return the Promise.all of an array containing the user and the createCart() call, and you'll have access to both in the next .then:

sequelize
  .sync()
  .then(result => {
    return User.findByPk(1);
  })
  .then(user => {
    if (!user) {
      return User.create({ name: 'Max', email: 'test@test.com' });
    }
    return user;
  })
  .then(user => {
    return Promise.all([user, user.getCart()]);
    // ^^^^^^^^^^^^^^^^^^^^^^^^
  })
  .then(([user, cart]) => {
    // ^^^^^^^^^^^^^^^^^^^^^^^^
    if (!cart) {
      return user.createCart();
    }
    return cart
  })
  .then(cart => {
    app.listen(3000);
  })
  .catch(err => {
    console.log(err);
  });

You might consider using async/await to make the code more readable:

try {
  const result = await sequelize.sync();
  const user = await User.findByPk(1) || await User.create({ name: 'Max', email: 'test@test.com' });
  const cart = await user.getCart() || await user.createCart();
  app.listen(3000);
} catch (err) {
  console.log(err);
}
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Why return a promise, just a tuple would do, wouldn't it? – Ruan Mendes Jun 12 '19 at 01:59
  • This is Javascript, what do you mean by tuple? – CertainPerformance Jun 12 '19 at 02:02
  • Thanks, it works. Is it possible to make this work without using "Promise.all" syntax ? – trogne Jun 12 '19 at 02:03
  • @JuanMendes : no, a simple array (not tuple) would not work cause in the background it will simply do `Promise.resolve([user, user.getCart()])` – trogne Jun 12 '19 at 02:04
  • 1
    @trogne You *could* nest it in another `.then` to avoid the `Promise.all`, but that would make for ugly code - `.then` chains are best written as flat as possible. (Avoid the then-as-callback antipattern) – CertainPerformance Jun 12 '19 at 02:04
  • @certainperformance any kind of tuple you want, an array with two items or an object with two properties https://medium.com/@wpcarro/tuples-in-javascript-57ede9b1c9d2 – Ruan Mendes Jun 12 '19 at 02:07
  • @CertainPerformance, nesting like that I guess : `then(user => { return user.getCart() .then(cart => { if (!cart) { return user.createCart(); } return cart }); })` – trogne Jun 12 '19 at 02:09
  • @trogne Promise.all has the same behavior, it just calls resolve on things that aren't promises. You can return for values or promises from then handlers – Ruan Mendes Jun 12 '19 at 02:11
  • Perfect ! Many thanks – trogne Jun 12 '19 at 02:12