如何在node.js中使这个函数异步

时间:2014-09-12 14:08:09

标签: node.js asynchronous

情况如下: 我是node.js的新手,我有一个包含多级json文件的40MB文件,如: [{},{},{}]这是一个对象数组(~7000个对象)。每个对象都有属性,其中一个属性也是一个对象数组

我编写了一个函数来读取文件的内容并进行迭代。我成功地获得了我想要的内容而不是可用性。我以为我编写了一个异步函数,允许节点在迭代数组时提供其他Web请求,但事实并非如此。如果有人能指出我做错了什么以及如何重写它以便我可以进行非阻塞迭代,我将非常感激。这是处理这种情况的函数:

    function getContents(callback) {

        fs.readFile(file, 'utf8', function (err, data) {

            if (err) {
                console.log('Error: ' + err);
                return;
            }

            js = JSON.parse(data);
            callback();
            return;
        });
    }

    getContents(iterateGlobalArr);

    var count = 0;
    function iterateGlobalArr() {

        if (count < js.length) {

            innerArr = js.nestedProp;

            //iterate nutrients
            innerArr.forEach(function(e, index) {

                //some simple if condition here

            });

            var schema = {
                //.....get props from forEach iteration
            }

            Model.create(schema, function(err, post) {

                if(err) {
                    console.log('\ncreation error\n', err);
                    return;
                }

                if (!post) {
                    console.log('\nfailed to create post for schema:\n' + schema);
                    return;
                }
            });

            count++;
            process.nextTick(iterateGlobalArr);
        }
        else {
            console.log("\nIteration finished");
            next();
        }

很明显我是如何测试上述情况的。我打开两个选项卡,一个加载此迭代,这需要一些时间,第二个与另一个节点路由,在迭代结束之前不会加载。所以基本上我写了一个阻止代码,但不知道如何重新考虑它!我怀疑只是因为回调中发生了一切,我无法释放事件循环来处理另一个请求......

2 个答案:

答案 0 :(得分:2)

您的代码几乎正确无误。你正在做的是无意中将所有项目添加到下一个tick ...仍然阻止。

重要的代码在这里:

          Model.create(schema, function(err, post) {

            if(err) {
                console.log('\ncreation error\n', err);
                return;
            }

            if (!post) {
                console.log('\nfailed to create post for schema:\n' + schema);
                return;
            }
        });

        // add EVERYTHING to the very same next tick!
        count++;
        process.nextTick(iterateGlobalArr);

当getContents()运行且count为0时,让我们假设您处于事件循环的刻度线A.您输入iterateGlobalArr并调用Model.create。因为Model.create是异步的,所以它立即返回,导致process.nextTick()将第1项的处理添加到下一个tick,让我们说B.然后它调用iterateGlobalArr,它执行相同的操作,添加项2到下一个刻度,它仍然是B.然后是第3项,依此类推。

您需要做的是将计数增量和process.nextTick()移动到Model.create()的回调中。这将确保在调用nextTick之前处理当前项目...这意味着在创建模型项目之后,下一个项目实际上被添加到下一个tick中...这将使您的应用程序有时间处理其中的其他内容。 iterateGlobalArr的固定版本在这里:

 function iterateGlobalArr() {

    if (count < js.length) {

        innerArr = js.nestedProp;

        //iterate nutrients
        innerArr.forEach(function(e, index) {

            //some simple if condition here

        });

        var schema = {
            //.....get props from forEach iteration
        }

        Model.create(schema, function(err, post) {

            // schedule our next item to be processed immediately.
            count++;
            process.nextTick(iterateGlobalArr);

            // then move on to handling this result.
            if(err) {
                console.log('\ncreation error\n', err);
                return;
            }

            if (!post) {
                console.log('\nfailed to create post for schema:\n' + schema);
                return;
            }
        });
    }
    else {
        console.log("\nIteration finished");
        next();
    }
}

另请注意,我强烈建议您在每次调用iterageGlobalArr时传入js和counter,因为它会使您的iterateGlobalArr更容易调试,除此之外,这是另一个故事。

干杯!

答案 1 :(得分:0)

Node是单线程的,因此async只会帮助您依赖其他系统/子系统来完成工作(shell脚本,外部数据库,Web服务等)。如果您必须在Node中完成工作,那么您将在执行此操作时阻止它。

可以为每个核心创建一个节点进程。此解决方案将导致仅阻止其中一个节点进程,而其余部分仍为请求提供服务,但此功能仍列为实验性http://nodejs.org/api/cluster.html

  

单个Node实例在单个线程中运行。要利用   用户有时希望启动集群的多核系统   节点进程处理负载。

     

群集模块允许您轻松创建子进程   所有共享服务器端口。