异步在节点不使用异步模块,有没有更好的方法? [英] Async in node without using the async module, is there a better way?

查看:259
本文介绍了异步在节点不使用异步模块,有没有更好的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要执行等效的 async.eachSeries()方法,但我不想添加一个依赖项如 require 'async')

I need to perform the equivalent of the async.eachSeries() method, but I did not want to add a dependency such as require('async').

所以我想出了下面的实现,我想知道是否有更好的方法来做到这一点?

So I came up with the implementation below, and I was wondering if there is a better way to do this?

it 'String::start_Process_Capture_Console_Out', (done)->

    runTest = (testData,next)->
        name          = testData.process_Name
        parameter     = testData.process_Parameter
        expected_Data = testData.expected_Data
        name.start_Process_Capture_Console_Out parameter, (data)->
            data.assert_Is(expected_Data)
            next()

    runTests = (testsData, next)->
        if testsData.empty() 
            next() 
        else 
            runTest testsData.pop(), ()-> runTests(testsData, next)

    testsData = [
                    {process_Name: 'echo' , process_Parameter: 'hello'       , expected_Data:'hello\n' }
                    {process_Name: 'echo' , process_Parameter: ['hello','me'], expected_Data:'hello,me\n' }
                    {process_Name: 'git'  , process_Parameter: ['xyz'       ], expected_Data:'git: \'xyz\' is not a git command. See \'git --help\'.\n' }
                    {process_Name: 'ls'   , process_Parameter: '.'           , expected_Data:'LICENSE\nREADME.md\nindex.js\nnode_modules\npackage.json\nsrc\ntest\n' }
                ]    

    runTests(testsData, done)

这里引用的是 start_Process start_Process_Capture_Console_Out string原型方法

For reference here are the start_Process and start_Process_Capture_Console_Out string prototype methods

String::start_Process = (args...)->
  args ?= []
  return child_process.spawn(@.str(),args)


String::start_Process_Redirect_Console = (args...)->
  args ?= []
  childProcess = @.start_Process(args)
  childProcess.stdout.on 'data', (data)->console.log(data.str().trim())
  childProcess.stderr.on 'data', (data)->console.log(data.str().trim())
  return childProcess  

String::start_Process_Capture_Console_Out =  (args... , callback)->
    consoleData = ""
    childProcess = @.start_Process(args)
    childProcess.stdout.on 'data', (data)->consoleData+=data
    childProcess.stderr.on 'data', (data)->consoleData+=data
    childProcess.on 'exit', ()->
      callback(consoleData)
    return childProcess

一个解决方案是添加原型到 Array 类,也许调用 async_Each_Series ,这样我们可以只有:

One solution would be to add a prototype to the Array class, maybe called async_Each_Series so that we could just have:

    testsData = [
                    {process_Name: 'echo' , process_Parameter: 'hello'       , expected_Data:'hello\n' }
                    {process_Name: 'echo' , process_Parameter: ['hello','me'], expected_Data:'hello,me\n' }
                    {process_Name: 'git'  , process_Parameter: ['xyz'       ], expected_Data:'git: \'xyz\' is not a git command. See \'git --help\'.\n' }
                    {process_Name: 'ls'   , process_Parameter: '.'           , expected_Data:'LICENSE\nREADME.md\nindex.js\nnode_modules\npackage.json\nsrc\ntest\n' }
                ]    

   testsData.async_Each_Series(runTest, done)


推荐答案

nodejs Array类已经有一个forEach方法,但它不需要回调

the nodejs Array class already has a forEach method, but it does not take a callback

[1,2,3,4].forEach (i) ->
    console.log i

如果您需要回调,请写(js this time)

if you need the callback, write (js this time)

function applyVisitor( data, visitor, next ) {
    // ...
}

或者也可以避免相关代码和过去的相关代码复制到您的代码中。

Or you can also avoid dependencies and cut-and-past copy the relevant code into yours.

(编辑:总之,是的,有一个更好的方法 - 写一个通用迭代器,并使用
它为这些测试,不要编写专用循环)

( in short, yes, there is a better way -- write a general-purpose iterator and use it for the these tests, do not write special-purpose loop just for this.)

我实现了applyVisitor
(也在 https://npmjs.org/package/aflow

My implementation of applyVisitor (also in https://npmjs.org/package/aflow)

/**
 * Repeatedly call func until it signals stop (returns truthy) or err.
 * Func is passed just a standard callback taking err and ret.
 * Returns via its callback the truthy value from func.
 */
function repeatUntil( func, callback ) {
    'use strict';

    callback = callback || function() {};

    function _loop( func, callback, callDepth ) {
        try {
            func( function(err, stop) {
                if (err || stop) return callback(err, stop);
                if (callDepth < 40) _loop(func, callback, callDepth + 1);
                else setImmediate(function() { _loop(func, callback, 0); });
            } );
        }
        catch (e) { callback(e); }
    }
    // note: 2.5x faster if callback is passed in to _loop vs pulled from closure

    _loop(func, callback, 0);
}


/**
 * visitor pattern: present all items to the visitor function.
 * Returns just error status, no data; to capture the results,
 * wrapper the visitor function.
 */
function applyVisitor( dataItems, visitorFunction, callback ) {
    'use strict';

    if (!Array.isArray(dataItems)) {
        return callback(new Error("expected a data array, but got " + typeof data));
    }

    var next = 0;
    repeatUntil(
        function applyFunc(cb) {
            if (next >= dataItems.length) return cb(null, true);
            visitorFunction(dataItems[next++], function(err) {
                cb(err, err);
            });
        },
        function(err, stop) {
            callback(err);
        }
    );
}

这篇关于异步在节点不使用异步模块,有没有更好的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆