同步异步调用异步调用

时间:2014-07-27 18:39:02

标签: javascript node.js rest asynchronous synchronization

我很难过

基本上,我有一个http REST API,我可以向其发出异步请求并提供回调。我还有一个Web前端,可以在任意位置异步调用此api。

问题是api需要'nonce'。每个后续请求的数字大于最后一个。以这种方式产生这个数字很容易。确保请求以正确的顺序到达..不是那么多。

我需要一种方法来支持我的api模块,我可以进行函数调用并提供回调。并且模块将处理随后的任何先前调用将在它发出新请求之前完成。

当然async模块允许同步运行异步函数,但它需要我知道我之前要触发的所有操作。使用我当前的系统,可能会在处理第一个请求时添加新请求。

一般来说api调用是这样的

// the api module
var nextNonceFunc = function() {
    var d = new Date();
    var seconds = Math.floor(d.getTime() / 1000);
    var nonce = seconds;
    return function() {
        return nonce++;
    }
}();

var privateAPI = function(key, secret) {
    var self = this;

    var api = new API(key, secret, nextNonceFunc);

    //information about the user
    self.getInfo = function (callback) {
        api.getInfo(callback);
    };
}

// ... bla bla set up routes ect. -> enter the server request callback
// server module

// we make an api instance
var api = new privateAPI(key, secreet);

// some time later we make an api call
api.getInfo(function(err, data){
    if (err) {
        //handle error
    }
    // dosomthing with the data
})

我正在寻找让privateAPI对象排队获取请求的方法。

2 个答案:

答案 0 :(得分:1)

在凯文指出存在async.queue后,我能够构建以下包装器

var async = require('async');


//actes as a wrapper for the passed api
module.exports = function(obj) {

    var self = this;

    var q = async.queue(function (task, callback) {
        var args = task.args;
        args.push(function(err, data){
            task.cb(err, data);
            if (err) return callback(err);
            callback();
        })
        obj[task.func].apply(obj, args);
    }, 1);

    var keys = Object.keys(obj);

    var buildFuncWrapper = function(i) {
       self[keys[i]] = function() {
            var args = Array.prototype.slice.call(arguments);
            var task = {
                func: keys[i],
                args: args.slice(0, args.length - 1),
                cb: args.slice(args.length - 1, args.length)[0]
            };
            q.push(task, function(){
                if (global.DEBUG) console.log("[SYNC WRAPPER] finished wrapped call to: ", keys[i]);
            })
        } 
    }

    var buildPropWrapper = function(i) {
        Object.defineProperty(self, keys[i], {
            get: function () { return obj[keys[i]]},
            writable : false,
            enumerable: true
        })
    }

    for (var i = 0; i < keys.length; i++) {
        if (typeof(obj[keys[i]]) === "function" ) {
            buildFuncWrapper(i);
        } else {
            buildPropWrapper(i);
        }
    }
}

基本上我可以将现有的API对象传递给它,它会通过队列转发对它的函数所做的所有调用,因为队列的并发性为1,一次只能处理一个调用。

之后,这是一个相当简单的事情,确保只存在这个包装的api对象的一个​​版本。

答案 1 :(得分:0)

某种客户端队列可以在这里工作。请注意,这是非常快速,肮脏和未经测试的,并且为了方便我假设jquery:

var ajaxQueue = function() {
    var _queue = [];
    var _isRunning = false;

    function isRunning() {
        return _isRunning;
    }

    function run(ajaxOptions) {
        _isRunning = true;
        $.ajax({
           url : ajaxOptions.url,
           method : ajaxOptions.method,
           //etc
           success : function() {
               _isRunning = false;
               if (ajaxOptions.callback) {
                   ajaxOptions.callback();
               }  

               if (queue.length) {
                   var next = queue.shift();
                   run(next);
               }
           }
        });
    }

    return {
         add : function(ajaxOptions){
             if (isRunning()) {
                 _queue.push(ajaxOptions);
                 // return the index of the current queue item
                  return _queue.length;
              } else {
                 run(ajaxOptions);
              }
         },
         remove : function(queueIndex) {
             delete _queue[queueIndex];
         }
    }
}