【问题标题】:node.js - turn an async function into a sync functionnode.js - 将异步函数转换为同步函数
【发布时间】:2012-07-25 02:39:59
【问题描述】:

像许多其他人一样,我想将第三方模块(Patio)的异步功能转换为同步功能。

function get_user_message_list(parameters, array, response)
{
var new_array = [];
for (var i in array) {

    var json = array[i];
    json['content']['users_seen'] = ["1757842565"];
    json['content']['users_not_seen'] = [];

    new_array.push(json);
}

console.log("NEW ARRAY :");
console.log(new_array);

response.writeHeader(200, {'Content-Type':'application/json'});
response.end(JSON.stringify(new_array));
}

function get_json_message(parameters, json)
{
console.log("JSON OBJECT :");
console.log(json);
var dataset = db.from(TABLES.USER).join(TABLES.MOVIE_LIST, {MLUserId: sql.URId}).join(TABLES.MOVIE, {MVId: sql.MLMovieId});

dataset.where('MLSeen={seen} AND MVSourceId={movie} AND MVSource={source} AND URId!={user}', {seen: 1, movie: json['content']['movie_id'], source: json['content']['movie_source'], user:parameters.FACEBOOK_ID}).all().then(function(users){
    if (users) {
        for (var j in users) {
            json['content']['users_seen'].push(users[j].URId);
        }
    }

    //console.log(json['content']['users_seen']);

    dataset.where('MLSeen={seen} AND MVSourceId={movie} AND MVSource={source} AND URId!={user}', {seen: 0, movie: json['content']['movie_id'], source: json['content']['movie_source'], user:parameters.FACEBOOK_ID}).all().then(function(users){
        if (users) {
            for (var j in users) {
                json['content']['users_not_seen'].push(users[j].URId);
            }
        }

        console.log(json);
    }, errorHandler);
}, errorHandler);
}

在 get_user_message_list 函数中,我迭代到一个数组中,并且对于每次迭代,我调用异步函数。在这个异步函数中,我使用 Patio 模块向 MySQL 数据库发出请求。但是如你所见,我必须在将结果发送到上一个函数后等待得到查询结果。

如何将 get_json_message 转换为 sync_get_json_message ? 谢谢。

【问题讨论】:

    标签: javascript node.js asynchronous sync synchronous


    【解决方案1】:

    当需要解决问题时,您可以并且应该将异步函数转换为行为类似于同步函数的东西。你不能永远不是正确的答案,不应该是程序员来回答的。

    所以,我最近在 nodeunit 模块中发现了一些可能对您有所帮助的代码。它触发异步函数,跟踪哪些函数已准备就绪。在所有请求都进入后,触发回调。这可能是您问题解决方案背后的想法(所以不,这不是最终解决方案)。

    async.forEachSeries = function (arr, iterator, callback) {
        if (!arr.length) {
            return callback();
        }
        var completed = 0;
        var iterate = function () {
            iterator(arr[completed], function (err) {
                if (err) {
                    callback(err);
                    callback = function () {};
                }
                else {
                    completed += 1;
                    if (completed === arr.length) {
                        callback();
                    }
                    else {
                        iterate();
                    }
                }
            });
        };
        iterate();
    };
    

    这个测试让我看到它是如何完成的:

    exports['series'] = function (test) {
        var call_order = [];
        async.series([
            function (callback) {
                setTimeout(function () {
                    call_order.push(1);
                    callback(null, 1);
                }, 25);
            },
            function (callback) {
                setTimeout(function () {
                    call_order.push(2);
                    callback(null, 2);
                }, 50);
            },
            function (callback) {
                setTimeout(function () {
                    call_order.push(3);
                    callback(null, 3, 3);
                }, 15);
            }
        ],
        function (err, results) {
            test.equals(err, null);
            test.same(results, [1, 2, [3, 3]]);
            test.same(call_order, [1, 2, 3]);
            test.done();
        });
    };
    

    编程愉快!

    【讨论】:

    • 这是一个非常短视的答案。这个问题的解决方案可能会导致比它解决的问题更多
    【解决方案2】:

    我一直在使用syncrhonize.js 并取得了巨大的成功。甚至还有一个挂起的拉取请求(效果很好)来支持具有多个参数的异步函数。比 node-sync imho 更好也更容易使用。额外的好处是它具有易于理解和详尽的文档,而 node-sync 没有。

    【讨论】:

      【解决方案3】:

      你不能也不应该。这将有效地阻止您的 Node.JS 服务器,并且您将失去 Node.JS 提供的所有优势。这也违背了 Node.JS 背后的整个异步思想。

      只需将callback 参数传递给您的函数:

      function get_json_message(parameters, json, callback){ // <---- note the callback
          // some other stuff
          dataset.where( ...
              // some other stuff
              dataset.where( ...
                  // some other stuff
                  // I've finished the job, call the callback
                  callback(); // <--- you can pass additional params here
              });
          });
      }
      

      然后这样称呼它:

      get_json_message( params, json, function() {
          console.log('Hello world!');
          // do whatever you like inside callback
      });
      

      【讨论】:

      • 您假设您正在运行 node.js 服务器而不是脚本...不要假设。
      • 不太喜欢笼统的回答,或者说语言或框架决定了应该如何做。任何花一点时间开发实际应用程序的人都会遇到这个问题,通常是因为库不使用回调,例如 express 中的 dynamicHelpers。
      • deasync 模块的文档中的这个 sn-p 描述了您“应该”的好情况。假设您维护一个公开 getData 的库。后台数据保存在一个文件中,因此您使用 Node.js 内置的 fs.readFileSync 实现了 getData。很明显 getData 和 fs.readFileSync 都是同步函数。有一天,你被告知将底层数据源切换到只能异步访问的 MongoDB。您被告知要避免激怒您的用户,getData API 不能更改为返回承诺或要求回调参数。您如何满足这两个要求?
      • @EricIhli 解决方案是永远不要使用同步 IO。在我看来,node.js 中甚至存在这样的东西是一个错误。那么切换的时候就没有问题了。 Deasync 并不是真正的 js。这是一个破解 V8 引擎内部的库。是的,当您破解源代码时,一切皆有可能。但是 node.js 从来就不是这样使用的。另外,在使用 lib 时我会非常小心。甚至作者本人也在 GitHub 上写:though it's just a hack and I'd strongly recommend not to use it for anything.
      • @freakish 即使有人认为解决方案是永远不要使用同步 IO,但很多人使用并不得不处理其他人编写的代码。执行重构并不总是可行的。除此之外,如果 getData API 不是 IO 怎么办?如果它是从内存读取但需要重构以从 IO 读取呢?
      猜你喜欢
      • 1970-01-01
      • 2015-06-25
      • 2018-03-21
      • 1970-01-01
      • 2018-01-11
      • 1970-01-01
      • 2015-10-15
      • 1970-01-01
      相关资源
      最近更新 更多