1

My question here may sound little repetitive. But I haven't found any answer on stackoverflow which can solve my problem.

I am returning a promise from one of my function. The promise will be resolved after getting some data from database. And will be rejected if there is no data in the db table. Also I have to do some processing on the fetched data before resolving the promise, that's why I am using callbacks.

My Code Snippet

return new Promise((resolve, reject) => {


            ResourceModel.getById(resource_ID).then((data) => {
                if (data.length > 0) {
                    console.log(data);
                    resolve(data);
                    console.log("Resolve Function Called");
                } else {
                    console.log("No data available");
                    reject(new Error("No data available"));
                }
            });
        });

ResourceModel.getById()

static getById(id) {
        const _transaction = cds.transaction();

        return _transaction.run(SELECT.from(Resource).where({ ID: id }));
    }

cds.transaction() is one of cds framework provided method by SAP.

What I expect it to do is after successfully fetching all the records it should call the provided callback where I have my processing logic written and call resolve() after the processing is done.

I am receiving the data in the callback, able to print Data available and the received data object end even the Promise Resolved on the console. But surprisingly the promise is not getting resolved

I can say the "promise is not getting resolved" because this returned promise will be collected in a Promise.all() by the framework (as stated in the official docs - https://cap.cloud.sap/docs/node.js/api#service-before) and return a response after resolving. But I am not getting any response (neither success nor failure). Postman stays in loading... state forever.

The above example works fine with setTimeout() example.

where am I going wrong?

Boghyon Hoffmann
  • 17,103
  • 12
  • 72
  • 170
arunava04
  • 67
  • 9
  • I'd suggest you show the whole request handler (including where the `Promise.all()` is) so we can see the whole request code from start to finish. FYI, it's really odd to make `getById()` use a promise internally and then expose a callback interface to the caller. Just return the promise. You also have NO error handling in `getById()`. If the promise rejects, you do nothing. – jfriend00 Feb 16 '20 at 06:41
  • I think you're making some wrong assumptions about where the problem is. We need to see more of the code involved in this request. If you're seeing "Data available" in the console and didn't see "No data available" before it, then your promise is getting resolved. So, the issue is probably in how that promise is getting used. We need to see that code. – jfriend00 Feb 16 '20 at 06:44
  • @jfriend00, Initially I was returning the promise from `getById()` method but that was also not working. I completely agree with you, from coding standard perspective that is what I need to be doing. Unfortunately I am unable to show the `Promise.all()` because that is being achieved by the sap's cap framework. And framework is taking care of all of these. – arunava04 Feb 16 '20 at 07:04
  • Actually you can think of this promise as one of the middleware method. Framework collects all these middleware methods in `Promise.all()` and returns a HTTP response upon resolving or rejecting any of the promise. – arunava04 Feb 16 '20 at 07:08
  • Unfortunately nothing in the code you posted above is wrong (apart from the obvious anti-pattern of callbackifying a promise then promisifying the callback again) so all we can say is that you don't need to change anything to make the promise resolve (as you said, it even prints "Promise Resolved"). Nothing is wrong with the code you posted above. There may be something wrong in code you did not post – slebetman Feb 16 '20 at 08:30
  • @slebetman, I have updated my code as it is supposed to be. Unfortunately this is the portion of code that I have written rest is handled by framework (like collecting all the promises and resolving). It is working perfectly if I use `setTimeout()` inside the promise instead of `getById()`. So it is difficult to assume that framework is going somewhere wrong. – arunava04 Feb 16 '20 at 08:51
  • Then it's likely Gopal's answer is correct. Your framework does not know what to do with the data you're returning maybe because it's in a format your framework don't understand (in typed based languages they call it wrong type). For example if your framework expects `data` to be a number but you're returning a string. Or another example if your framework expects `data` to be an object that looks like `{success:true, result: [...]}` but you are returning `[...]` or another example your framework expect `data` to be `[Object, Object]` but you are returning `[Row, Row]` etc – slebetman Feb 16 '20 at 10:19
  • Are you sure your framework expects promises not a function that accepts a callback? – slebetman Feb 16 '20 at 10:20
  • Are you sure your framework expects promises not a function that return a promise? – slebetman Feb 16 '20 at 10:20
  • @slebetman, I don't think datatype can be an issue because as I stated in the question also that if I use `setTimeout()` instead of `ResourceModel.getById()` and inside the callback of `setTimeout()` I provide `resolve(true)` or `resolve("success")` everything works. It only stops working when the `ResourceModel.getById()` method coming into the picture. yes, in the [documentation](https://cap.cloud.sap/docs/node.js/api#service-before) it is told that, always return a promise if your handlers trigger asynchronous tasks and all promises returned are collected in a `Promise.all`. – arunava04 Feb 16 '20 at 10:30
  • Please show the code where this hooks into your framework so we can check how you're doing that with the framework documentation. If this is a `srv.before()` call, then show your actual code for that. – jfriend00 Feb 16 '20 at 15:25
  • Avoid the [`Promise` constructor antipattern](https://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! – Bergi Dec 26 '20 at 20:40

2 Answers2

0

I have faced this type of error while making API calls or fetching data from the db. Generally the issue used to be type mismatch of called resources or header is having wrong return type. It would be good to have console.log in getById() and see what's happening thete in the stack trace.

Gopal Anand
  • 99
  • 4
  • 14
0

first of all, add .catch() to get rejected value.

function asyncOpr = () => { 
    return new Promise((resolve, reject) => {
        ResourceModel.getById(resource_ID).then((data) => {
                    if (data.length > 0) {
                        console.log(data);
                        resolve(data);
                        console.log("Resolve Function Called");
                    } else {
                        console.log("No data available");
                        reject(new Error("No data available"));
                    }
            }).catch(err => { /* handle error */ })
        });
  }

The reason why you may not be getting the resolved value would be how you are using this function. Correct implementation would be:

function foo() {
  asyncOpr().then( val => console.log(val))
            .catch( err => console.log(err))
}

Also, see using async/await.

laxman
  • 1,781
  • 4
  • 14
  • 32