如何在没有延迟反模式的情况下将jQuery $ .ajax调用转换为Bluebird promises

时间:2014-06-19 19:54:22

标签: javascript promise bluebird

现在我在核心文件中使用promise.deferred。这允许我在中心位置解决承诺。我一直在读我可能正在使用反模式,我想知道它为什么不好。

所以在我的 core.js 文件中我有这样的函数:

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;
}

然后在我的 getLocation.js 文件中,我有以下内容:

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

在阅读了Bluebird文档和许多关于延迟反模式的博客文章后,我想知道这种模式是否切实可行。我可以将其更改为以下内容:

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();
    });

我想我对使用jquery为调用处理xhr请求的中央库的最佳方法感到困惑,但Bluebird是为了承诺。

2 个答案:

答案 0 :(得分:19)

你可以在一个jQuery上调用Promise.resolve,然后让Bluebird吸收它:

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

你也可以直接在Bluebird链中返回jQuery promises并让它同化它。

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

下面的代码很接近,但您不需要捕获TimeoutError,因为jQuery ajax不会抛出这些代码。至于捕捉取消错误。无论如何,如果您希望取消请求,这是最佳做法。

答案 1 :(得分:3)

要将thenable转换为Bluebird承诺,您可以使用这样调用Promise.resolve

-module(simple_server).

-export([start/0]).

keep_alive() ->
    receive
        Any -> io:format("Listening socket: ~p~n",[Any])
    end.


start() ->
    ssl:start(),
    spawn(fun() ->
        start_parallel_server(3333),
        keep_alive()
    end).


start_parallel_server(Port) ->
    case ssl:listen(Port, [
        binary,
        {packet, 0},
        {reuseaddr, true},
        {active, true},
        {certfile,"../etc/server/cert.pem"},
        {keyfile,"../etc/server/key.pem"},
        {cacertfile,"../etc/server/cacerts.pem"},
        {verify,verify_peer},
        {fail_if_no_peer_cert,true}
    ]) of
        {ok,Listen} ->
            spawn(fun() -> par_connect(Listen) end);
        {error,Reason} ->
            io:format("error ~p~n",[Reason])
    end.



par_connect(Listen) ->
    case ssl:transport_accept(Listen) of
        {ok,Socket} ->
            spawn(fun() -> par_connect(Listen) end),
            ssl:ssl_accept(Socket),
            print_cert(Socket),
            get_request(Socket,[]);
        {error,Reason} ->
            io:format("Listening stopped (~p)~n",[Reason])
    end.

print_cert(Socket) ->
    case ssl:peercert(Socket) of
        {ok,Cert} ->
            io:format("Certificate: ~p~n",[Cert]);
        {error,Reason} ->
            io:format("Certificate error ~p~n",[Reason])
    end.


get_request(Socket,L) ->
    receive
        {ssl, Socket, Bin} ->
            io:format("Server received: ~p~n",[Bin]),
            get_request(Socket,L);
        {ssl_closed, Socket} ->
            io:format("Socket did disconnect~n");
        Reason ->
            io:format("Client error: ~p~n",[Reason])
    end.

奖金部分:

大多数JQuery AJAX函数都是可以使用的,但是为了您的信息,如果要将需要回调的函数转换为promise,可以使用Promise.fromNode。将使用参数var promise = Promise.resolve($.getJSON(...)); 调用回调,这在Node.js世界中是惯例:

err, result

如果回调没有预料到第一个参数的潜在错误,你可以解决这个问题:

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