ErikR
ErikR

Reputation: 52039

a jQuery promise that always succeeds?

I have this code jQuery code fragment:

$.get('/api/' + currentPage).done(function(data) { ... })
                            .fail(...)

I want to replace $.get('/api/'+currentPage) with a promise that always succeeds and returns a specific value for data. Something like:

let myData = { ... }  // value of data I want to pass to the done function

(new AlwaysSucceeds(myData)).done(function(data) { ... })
                            .fail(...)

I could cobble up a dummy object, or I could extract out the done function but I want to keep changes to the code to a minimum.

Is there a way to do this?

UPDATE: To help clarify what's going, the code I am working with is (here). Normally this app is served from a nodejs server which implements the /api/... call, but I am converting it to be served from a static page server. I know what is going to be returned from the $.get call. To keep changes to the code clean I simply want to change that line to:

let myData = {...}

// $.get('/api/' + currentPage) -- comment out the $.get call
(SOMETHINGHERE(myData)).done(function(data) {

The SOMETHINGHERE expression needs to implement .done(f) which will call the function f with myData and then return some object which implements .fail(...) which does nothing.

Upvotes: 0

Views: 347

Answers (4)

jfriend00
jfriend00

Reputation: 707516

You can just replace $.get(...) with a function that returns a promise that is already resolved with the data you already have. And, the shortest way to get an already resolved jQuery promise, resolved with a particular value, is this:

$.when(myData).done(...)

The more text book way to do it in jQuery is:

$.Deferred().resolve(myData).done(...)

And, if you care to switch your logic to the the ES6 standard (instead of the non-standard jQuery promise behaviors), then you could use this:

Promise.resolve(myData).then(...).catch(...)

Upvotes: 3

HMR
HMR

Reputation: 39280

It's not clear what you actually want but be carufull using jQuery Deferred with native promises, the deferred has some non standard methods that native promises don't have.

So to be save I always assume there is a thenable, something that has a then with that you can pretty much do whatever you want.

jQuery Deferred do not behave like native promises either (depending on version):

$.Deferred().reject("hello world")
.then(
  undefined
  ,x=>x
)
.then(
  x=>console.log("Never happens",x)
)

Promise.reject("hello world")
.then(
  undefined
  ,x=>x
);
.then(
  x=>console.log("Well behaved",x)
);

Promise.resolve().then(x=>{throw "nope"})
.then(undefined,err=>console.warn(err));

$.Deferred().resolve().then(x=>{throw "nope"})//crashes
.then(undefined,err=>err);

So it will be saver to use native promises and polyfill with something that behaves like native.

To answer the question about non failing promise, if you want to make a request but return a default when it rejects and keep returning the same once resolves or rejects you can do:

const get = (p=>{
  (url) => {
    p = p ||
    //return native promise or properly polyfilled one
    Promise.resolve($.get(url))
    .then(
      undefined,
      _=> {defaultobject:true}
    );
    return p;
  }
})();

Your get function will return a native promise so no fail, done and other things that are non standard. Combining "promises" from different libraries and native promises it would be best to only use then

Upvotes: 1

Kevin Ji
Kevin Ji

Reputation: 10499

Since jQuery Ajax functions just return $.Deferred objects, you can just substitute an immediately-resolved Deferred:

$.Deferred().resolve(myData).then(...)

In this particular case, if you want to make it easy to switch between synchronous and asynchronous code, and you have access to async/await, you can just use those directly:

try {
    const data = await Promise.resolve($.get('/api/' + currentPage));
    // code in done
} catch (err) {
    // code in fail
}

would become

try {
    const data = myData;
    // code in done
} catch (err) {
    // code in fail (never runs unless other code throws exceptions)
}

Upvotes: 1

Vipin Kumar
Vipin Kumar

Reputation: 6546

You can achieve this by implementing AlwaysSuceeds constructor function. Please see below example.

function AlwaysSucceeds(data) {
  this.data = data; 
}

AlwaysSucceeds.prototype.done = function(fn) {
  fn(this.data);
  return this;
}

AlwaysSucceeds.prototype.fail = function(fn) {
  return this;
}


var myData = { 
  a: 1 
};

(new AlwaysSucceeds(myData)).done(function(data) { 
  console.log(data)
}).fail(function(data){ 

})

Upvotes: 1

Related Questions