2

I have seen lots of very similar questions but don't give a direct answer for actually waiting. I have a script based on Bookshelf.js;

var Product = bookshelf.Model.extend({
  tableName: 'amazon_products',
  hasTimestamps: true,
  virtuals: { //https://github.com/bookshelf/bookshelf/wiki/Plugin:-Virtuals
    hasSiteProduct: function() {
      var product_references = this.related('siteProductsReferences').fetch()
      return product_references.length;
    }
  }

});

I have setup a virtual property that will simply count the OneToMany relations of the model and return the count. But in this case it looks like this.related('siteProductsReferences').fetch() has to take sometime before returning a response. The this.related('siteProductsReferences').fetch() also has a promise that can look like this;

this.related('siteProductsReferences').fetch().then(function(result) {
  // ...
});

I am building this to be returned via an API. If I just add return this.related('siteProductsReferences').fetch() to the method I get a full l get;

,"hasSiteProduct":{"isFulfilled":false,"isRejected":false}

So clearly the callback has not finished.

  • Probably a duplicate of [How do I return response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call). – jfriend00 Aug 31 '17 at 04:22
  • 1
    `this.related('siteProductsReferences').fetch()` apparently returns a promise. You use `.then()` on a promise to register a callback that will be called when it has a value. – jfriend00 Aug 31 '17 at 04:23
  • Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – peteb Aug 31 '17 at 04:24
  • If fetch() returns a Bluebird promise it could be like this: " hasSiteProduct: function(cb) { this.related('siteProductsReferences').fetch().then(refs=>refs.length).asCallback(cb); } " But I would use promises instead of callbacks. Also "fetch().fetch()" - probably a typo. – Dzenly Aug 31 '17 at 04:30

1 Answers1

1

Because the database operation returns a promise, your function also needs to return a promise - there's no getting out of that, you have to pass the promise back to the caller which will need to .then() it.

Below does not work because you cannot access .length on a promise that has not been fulfilled yet:

hasSiteProduct: function() {
    var product_references = this.related('siteProductsReferences').fetch()
    return product_references.length;
}

However you can do this:

hasSiteProduct: function() {
    var product_references_length_promise = 
    this.related('siteProductsReferences').fetch()
    .then(product_references => {
        return product_references.length;
    })

    // return the promise - it has not completed yet, client must .then() it
    return product_references_length_promise; 
}

the client needs to .then() the promise returned like so:

hasSiteProduct().then(num_product_references => {
    // do something with num_product_references 
})

For what it's worth I think you may be going down the wrong path in building an in-memory model of your data. This has been a technique favored by Object Oriented developers when dealing with data from a database, but I've always found very hard to make this work in an elegant way - it takes a lot of effort to build the model and the effort doesn't really pay off.

saille
  • 9,014
  • 5
  • 45
  • 57