문제

I am not able to get chained promises to work as per RSVP documentation. I have a case where I am trying to fetch some data from the server. If for some reason an error occurs, I want to fetch the data from a local file.

I am trying to chain promises for that.

I have created a simplified example. The below example will give an output but is not what I want. http://emberjs.jsbin.com/cobax/3

App.IndexRoute = Em.Route.extend({
  model: function() {
    return Ember.$.getJSON('http://test.com/search')

    .then(undefined, function(errorObj, error, message) {
        return new Promise(function(resolve, reject) {
          resolve(model);
        }).then(function(response) {
          console.info(response.articles);
          return response.articles;
        });
    });
  }
});

This example is what I want but it wont call the final 'then'. http://emberjs.jsbin.com/cobax/3

App.IndexRoute = Em.Route.extend({
  model: function() {
    return Ember.$.getJSON('http://test.com/search')

    .then(undefined, function(errorObj, error, message) {
        return new Promise(function(resolve, reject) {
          resolve(model);
        });
    })

    .then(function(response) {
      console.info(response.articles);
      return response.articles;
    });
  }
});

Basically I want to handle the server/local response from the last 'then' method. I also want keep all the callbacks in a single level.

What is the error in the second code snipped?


Update

As @marcio-junior mentioned, the jquery deferred was the issue. Here is the fixed bin from him. http://jsbin.com/fimacavu/1/edit

My actual code doesn't return a model object, it makes another getJSON request to a json file. I can't replicate this in a bin as I dont think js bin allows us to host static files. Here is the code but it wont work. It fails due to some js error.

App.IndexRoute = Em.Route.extend({
  model: function() {
    var cast = Em.RSVP.Promise.cast.bind(Em.RSVP.Promise);
    return cast(Ember.$.getJSON('http://test.com/search'))

    .then(undefined, function(errorObj, error, message) {
        //return Em.RSVP.resolve(model);
        return cast(Ember.$.getJSON('data.json'));
    })

    .then(function(response) {
      console.info(response.articles);
      return response.articles;
    });
  }
});

Can you help me with this? These promises are a bit tricky to understand.

Here is the error stack I see

XMLHttpRequest cannot load http://test.com/search. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. localhost/:1
Error while loading route: index ember-canary-1.7.0.js:3916
logToConsole ember-canary-1.7.0.js:3916
defaultActionHandlers.error ember-canary-1.7.0.js:39681
triggerEvent ember-canary-1.7.0.js:39763
trigger ember-canary-1.7.0.js:42317
Transition.trigger ember-canary-1.7.0.js:42162
(anonymous function) ember-canary-1.7.0.js:42017
invokeCallback ember-canary-1.7.0.js:10498
publish ember-canary-1.7.0.js:10168
publishRejection ember-canary-1.7.0.js:10596
(anonymous function) ember-canary-1.7.0.js:15975
DeferredActionQueues.flush ember-canary-1.7.0.js:8610
Backburner.end ember-canary-1.7.0.js:8082
(anonymous function)
도움이 되었습니까?

해결책

You are returning a RSVP promise to a jquery deferred. And jquery deferreds doesn't have the feature of fulfill a rejected promise. So you need to update your sample to use Em.RSVP.Promise.cast(deferred), to transform a deferred in a RSVP promise, which implements the promises/a+ spec and does what you want:

App.IndexRoute = Em.Route.extend({
  model: function() {
    return Em.RSVP.Promise.cast(Ember.$.getJSON('http://test.com/search'))
      .then(undefined, function() {            
        return getDefaultData();
      })
      .then(function(response) {
        console.info(response.articles);
        return response.articles;
      });
  }
});

Your updated jsbin

다른 팁

Here is the final route code I used. Its simply checks for the my apps api for the results. If its not present, I take the static results from a sample json file. The parsing of the response happens at the end irrespective of where it came from.

var App.IndexRoute = Ember.Route.extend({
    model: function() {
        var cast = Em.RSVP.Promise.cast.bind(Em.RSVP.Promise);
        return  cast(Ember.$.getJSON('http://test.com/search'))

        .then(undefined, function(error) {
            console.info(error);
            return Ember.$.getJSON('assets/data.json');
        })

        .then(function(response) {
            console.info(response);
            return JSON.parse(response);
        });
    }
});
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top