Home > database >  Promise pending even after its resolved
Promise pending even after its resolved

Time:10-10

I want to get the array of rooms and assign it to each property wrt their property_id, but the value returned is a pending promise. Not sure what's wrong. Although when I log the rooms inside the then it does log the value correctly. The result of console.log(property) is given below.

const vendorProfile = catchAsync(async (req, res, next) => {
  await passport.authenticate("vendor-jwt", { session: false }, (err, user, info) => {
    if (err) {
      res.error = err || info.message;
      return next(401);
    }
    if (!user) {
      res.error = info.message;
      return next(401);
    }
    return Promise.resolve(
      getVendorProfileInfo(user._id)
        .then((result) => {
          if (result == "error") {
            res.error = "Failed to fetch Vendor Profile";
            next(500);
          }
          return getPropertyByVendorId(result._id).then((prop) => {
            for (const property of prop) {
              property._doc.property_rooms = getAllRooms(property._id).then((rooms) => rooms);
              console.log(property);
            }
            res.message = "Vendor Profile fetched successfully";
            res.data = {
              vendor_info: result,
              vendor_properties: prop,
            };
            return next(200);
          });
        })
        .catch((err) => {
          Logger.error(err);
          res.error = "Failed to get vendor profile";
          return next(500);
        })
    ).catch((err) => {
      Logger.error(err);
      res.error = "Failed to get vendor profile";
      return next(500);
    });
  })(req, res, next);
});

This is the function to get all the rooms for that property_id:

const getAllRooms = (propertyId) => {
  return Promise.resolve(Room.find({ property_id: propertyId }).then((result) => result)).catch((err) => {
    Logger.error(err);
    return "error";
  });
};

Here is my console.log(property):

{
  property_basic_info: {
    property_name: 'Welcome',
    property_star_rating: 1,
    property_booking_since: 2021,
    property_channel_manager: ''
  },
  property_location: {
    property_geo_loc: { coordinates: [Array], type: 'Point' },
    property_locality: 'bhandup',
    property_address: 'MAHAVIR UNIVERSE',
    property_country: 'India',
    property_state: 'Maharashtra',
    property_city: 'Mumbai',
    property_zip_code: '400078'
  },
  property_contact_details: { phone_no: '7059462868', email: '[email protected]' },
  property_amenities: {
    basic_facilities: [ 'Electricity', 'Air Conditioning', 'Elevator/ Lift', 'Bathroom' ],
    general_services: [ 'Food', 'Bellboy service' ],
    outdoor_activities_sports: [],
    common_area: [],
    food_drink: [],
    health_wellness: [],
    business_center_conference: [],
    beauty_spa: [],
    security: []
  },
  property_policies: {
    checkin_time: '10:06',
    checkout_time: '22:06',
    cancellation_policy: 'Free cancellation upto 48 hrs'
  },
  property_rules: {
    id_proof: {
      acceptable_identity_proofs: 'Adhaar',
      unacceptable_identity_proofs: 'Adhaar',
      allow_same_id: true
    },
    guest_profile: [
      [Object], [Object],
      [Object], [Object],
      [Object], [Object],
      [Object]
    ],
    general_safety_hygiene_guidelines: [],
    room_safety_hygiene: [],
    social_distancing: [],
    food_drinks_hygiene: [],
    property_restrictions: [],
    pet_policy: [],
    guest_suitabilty: [],
    checkin_checkout_policy: [],
    extra_bed_policy: [ [Object] ],
    custom_policy: []
  },
  property_finance_legal: { gst_details: '29AAACR4849R2ZG' },
  property_status: 1,
  property_photo_id: [],
  _id: 61607791b1af193c7b8b9f08,
  vendor_id: 61607775b1af193c7b8b9f07,
  createdAt: 2021-10-08T16:53:37.734Z,
  updatedAt: 2021-10-08T16:53:37.734Z,
  __v: 0,
  property_rooms: Promise { <pending> }
}

Thanks in advance.

CodePudding user response:

That's because you are logging the promise outside the then method.

The promise is resolved async so outside then it is not resolved yet.

you have to change this line:

property._doc.property_rooms = getAllRooms(property._id).then((rooms) => rooms);
console.log(property);

to

property._doc.property_rooms = getAllRooms(property._id).then((rooms) => console.log(rooms));

or use async/await to work with it like sync values

CodePudding user response:

I would suggest that you break your task into manageable, coherent sub-tasks. And "manageable" means "short", and "coherent" means "returning a promise".

First contender is passport.authenticate. It's not returning a promise at all, it's a traditional callback-based function. We can convert it into a promise-based function like this:

passport.authenticateAsync = function (jwt, options) {
  return new Promise( (resolve, reject) => {
    this.authenticate(jwt, options, (err, user, info) => {
      if (err) return reject(err);
      if (!user) return reject(info.message);
      resolve(user);
    });
  });
};

Now we can call that as passport.authenticateAsync("vendor-jwt", { session: false }) and get a promise that resolves to a user, or rejects.

Next up, getVendorProfileInfo. Apparently this already returns a promise, but sometimes that promise's value can be "error", in which case it's actually an error. So let's wrap it in a promise that actually rejects when there is an error.

const getVendorProfileById = vendorId =>
  getVendorProfileInfo(vendorId).then(profile => {
    if (profile === "error") throw new Error("Failed to fetch Vendor Profile with ID "   vendorId);
    return profile;
  }
);

Finally, there's getPropertyByVendorId, which is your main point. You seem to want something that takes a vendor ID, and returns all rooms of all properties of that vendor. Promise#all, Array#map and getAllRooms gets us a single promise that resolves with all rooms for a vendor, or rejects with an error:

const getRoomsByVendorId = vendorId =>
  getPropertyByVendorId(vendorId).then(properties => 
    Promise.all(properties.map(property => getAllRooms(property._id)))
  );

And now it's straight-forward to wrap all that in a route handler:

const vendorProfile = async (req, res, next) => {
  try {
    const user = await passport.authenticateAsync("vendor-jwt", { session: false });
    try {
      res.data = {
        vendor_info: await getVendorProfileById(user._id),
        vendor_properties: await getRoomsByVendorId(user._id),
      };
      return next(200);
    } catch (err) {
      Logger.error(err);
      return next(500);
    }
  } catch (err) {
    res.error = err;
    return next(401);
  }
};
  • Related