How to cast jQuery $.ajax calls to Bluebird promises without the deferred anit-pattern

十年热恋 提交于 2019-12-21 03:17:09

问题


Right now I use promise.deferred in a core file. This allows me to resolve promises at a central location. I've been reading that I may be using an anti-pattern and I want to understand why it is bad.

so in my core.js file I have functions like this:

var getMyLocation = function(location) {    
    var promiseResolver = Promise.defer();

    $.get('some/rest/api/' + location)
        .then(function(reponse) {
            promiseResolver.resolve(response);
        )}
        .catch(function(error) {
            promiseResolver.reject(error);
        });

     return promiseResolver.promise;
}

And then in my getLocation.js file I have the following:

var core = require('core');
var location = core.getMyLocation('Petersburg')
    .then(function(response) {
        // do something with data
    }).catch(throw error);

After reading the Bluebird docs and many blog posts about the deferred anti-pattern I wonder if this pattern is practical. I could change this to the following:

core.js

var getMyLocation = function(location) {
    var jqXHR = $.get('some/rest/api/' + location);
    return Promise.resolve(jqXHR)
        .catch(TimeoutError, CancellationError, function(e) {
            jqXHR.abort();
            // Don't swallow it
            throw e;
        });

getLocation.js

var location = core.getMyLocation('Petersburg')
    .then(function(response) {
        // do something
    })
    .catch(function(error) {
        throw new Error();
    });

I guess I'm confused by what is the best way to have a central library that handles xhr requests using jquery for the calls, but Bluebird for the promises.


回答1:


You can call Promise.resolve on a jQuery thenable and have Bluebird assimilate it:

var res = Promise.resolve($.get(...)); // res is a bluebird Promise

You can also return jQuery promises directly inside a Bluebird chain and have it assimilate it.

myBluebirdApi().then(function(){
    return $.get(...);
}).then(function(result){
    // The jQuery thenable was assimilated
});

Your code below is close, but you don't need to catch TimeoutError since jQuery ajax won't throw those. As for catching cancellation error. This is best practice anyway for what you're doing if you ever expect to need to cancel the request.




回答2:


To convert a thenable to a Bluebird promise, you can use can call Promise.resolve like this:

var promise = Promise.resolve($.getJSON(...));

Bonus section:

Most JQuery AJAX functions are thenable, but for your information, if you want to convert a function that expects a callback to a promise, you can use Promise.fromNode. The callback will be called with the arguments err, result as is convention in the Node.js world:

var promise = Promise.fromNode(function (callback) { request(url, callback); });

If the callback doesn't expect a potential error for its first argument, you can work around that:

var promise = Promise.fromNode(function (callback) {
  FB.api(url, function(response) { callback(response ? response.error : "no response", response); });
});


来源:https://stackoverflow.com/questions/24315180/how-to-cast-jquery-ajax-calls-to-bluebird-promises-without-the-deferred-anit-p

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!