2012-07-17 17 views
6
function indexArticles(callback) { 
    fs.readdir("posts/", function(err, files) { 
    async.map(files, readPost, function(err, markdown) { 
     async.map(markdown, parse, function(err, results) { 
     async.sortBy(results, function(obj, callback) { 
      callback(err, obj.date); 
     }, function(err, sorted) { 
      callback({"articles": sorted.reverse()}); 
     }); 
     }); 
    }); 
    }); 
} 

मैं यह पता लगाने के लिए इस खूबसूरत बनाने के लिए कैसे करने के लिए कोशिश कर रहा हूँ उपयोग करने के लिए प्रवाह प्रवाह संरचनाओं। ऐसा लगता है जैसे मैं async.waterfall का उपयोग करता हूं, उदाहरण के लिए, जिसके परिणामस्वरूप थोड़ा और कोड होता है, जिसमें प्रत्येक चरण को किसी अज्ञात फ़ंक्शन में लपेटा जाता है। उदाहरण के लिए, यह सिर्फ पहले दो झरने के साथ नेस्टेड संस्करण की तर्ज है:पुनर्रचना नेस्टेड कॉलबैक, Node.js, async

function indexArticles(callback) { 
    async.waterfall([ 
    function(callback) { 
     fs.readdir("posts/", function(err, files) { 
     callback(err, files) 
     }) 
    }, 

    function(files, callback) { 
     async.map(files, readPost, function(err, markdown) { 
     callback(err, markdown) 
     }) 
    }]) 
} 

आप यह कैसे बढ़ेगी?

यदि आंशिक रूप से बहस नहीं केवल बाएं से, तो मैं क्या कर देख सकते हैं, उदाहरण के लिए लागू करने के लिए एक तरह से, थे

function indexArticles(callback) { 
    async.waterfall([ 
    async.apply(fs.readdir, "posts/"), 
    async.apply(async.map, __, readPost), 
    async.apply(async.map, __, parse), 
    // etc... 
    ]) 
} 
+0

जबकि 'वाटरफाल' अधिक पात्रों के साथ समाप्त हो सकता है, मुझे लगता है कि यह और अधिक पठनीय तरीके से समाप्त हो जाएगा। उन सभी एनन कार्यों में सहायता के लिए 'लागू करें' भी देखें। –

+0

क्या आप अभी भी पोस्ट किए गए झरना उदाहरण को देख सकते हैं और मुझे बता सकते हैं कि क्या मैं इसे सही कर रहा हूं? –

उत्तर

6

के रूप में आप दोनों बहस के लिए बाध्य करने की जरूरत है यह, एक दिलचस्प समस्या है बाएं और अपने इटरेटर फ़ंक्शंस के दाईं ओर, इसलिए न तो bind/न ही bindRight (जिनमें से स्टैक ओवरव्लो पर कुछ कार्यान्वयन हैं) आपके लिए काम करेंगे। वहाँ आप के लिए कुछ विकल्प यहाँ है:

(1) सबसे पहले, अपने async.waterfall उदाहरण में, आपके पास:

function(callback) { 
    fs.readdir("posts/", function(err, files) { 
    callback(err, files) 
    }) 
} 

जो एक ही है के रूप में:

function(callback) { 
    fs.readdir("posts/", callback) 
} 

Function.bind और इस विधि का उपयोग , आपका पूरा फ़ंक्शन indexArticles लिखा जा सकता है:

function indexArticles(callback) { 
    async.waterfall([ 
    fs.readdir.bind(this, 'posts/'), 
    function(files, cb) { async.map(files, readPost, cb); }, 
    function(text, cb) { async.map(text, parse, cb); }, 
    function(results, cb) { async.sortBy(results, function(obj, callback) { 
     callback(null, obj.date); 
    }, cb) } 
    ], function(err, sorted) { 
    callback({"articles": sorted.reverse()}); 
    }); 
}; 

जो थोड़ा छोटा है।

(2) यदि आप वास्तव में रैपिंग फ़ंक्शंस से बचना चाहते हैं, तो आप आंशिक फ़ंक्शन एप्लिकेशन का उपयोग कर सकते हैं। सबसे पहले, अपने फ़ाइल के शीर्ष पर (या एक मॉड्यूल, आदि में), एक समारोह partial बुलाया परिभाषित:

var partial = function(fn) { 
    var args = Array.prototype.slice.call(arguments, 1); 
    return function() { 
    var currentArg = 0; 
    for(var i = 0; i < args.length && currentArg < arguments.length; i++) { 
     if (args[i] === undefined) 
     args[i] = arguments[currentArg++]; 
    } 
    return fn.apply(this, args); 
    }; 
} 

यह समारोह एक समारोह और तर्क के किसी भी संख्या लेता है, और के साथ बहस सूची में undefined मूल्यों को बदल देता है जब समारोह कहा जाता है तो वास्तविक तर्क। इसके बाद आप इस तरह उपयोग होगा:

function indexArticles(callback) { 
    async.waterfall([ 
    fs.readdir.bind(this, 'posts/'), 
    partial(async.map, undefined, readPost, undefined), 
    partial(async.map, undefined, parse, undefined), 
    partial(async.sortBy, undefined, function(obj, callback) { 
     callback(null, obj.date); 
    }, undefined) 
    ], function(err, sorted) { 
    callback({"articles": sorted.reverse()}); 
    }); 
} 

तो, partial(async.map, undefined, readPost, undefined) एक समारोह है कि, जब fn(files, callback) के रूप में Async पुस्तकालय द्वारा कहा जाता है, यह files में पहली undefined के लिए भर जाता है, और दूसरा undefined के लिए callback देता है, में समाप्त होने वाले async.map(files, readPost, callback) पर कॉल करें।

(3) वहाँ भी this StackOverflow answer पर Function.prototype, आप सिंटैक्स का उपयोग करने की अनुमति के लिए partial का एक संस्करण है: async.map.partial(undefined, readPost, undefined); हालांकि, मैं शायद इस तरह से Function.prototype संशोधित करने के खिलाफ अनुशंसा करता हूं, और केवल एक समारोह के रूप में partial का उपयोग करें।

अंत में, यह आपके ऊपर है कि कौन सी विधि सबसे अधिक पढ़ने योग्य और रखरखाव योग्य है।

2

ऐसा लगता है कि मैं ब्रेंडन के जवाब के साथ कुछ ओवरलैप है, लेकिन यहाँ मेरी ले रहा है:

var async = require("async") 

//dummy function 
function passThrough(arg, callback){ 
    callback(null, arg) 
} 

//your code rewritten to only call the dummy. 
//same structure, didn't want to think about files and markdown 
function indexArticles(callback) { 
    passThrough("posts/", function(err, files) { 
    async.map(files, passThrough, function(err, markdown) { 
     async.map(markdown, passThrough, 
     function(err, results) { 
      async.sortBy(results, function(obj, callback) { 
      callback(err, obj); 
     }, 
     function(err, sorted) { 
      callback({"articles": sorted.reverse()}); 
     }); 
     }); 
    }); 
    }); 
} 
indexArticles(console.log) 

//version of apply that calls 
//fn(arg, arg, appliedArg, apliedArg, callback) 
function coolerApply(fn) { 
    var args = Array.prototype.slice.call(arguments, 1); 
    return function() { 
    var callback = Array.prototype.slice.call(arguments, -1) 
    var otherArgs = Array.prototype.slice.call(arguments, 0, -1) 
    return fn.apply(
     null, otherArgs.concat(args).concat(callback) 
    ); 
    }; 
}; 

//my version of your code that uses coolerAppl 
function indexArticles2(callback){ 
    async.waterfall([ 
    async.apply(passThrough, "posts/"), 
    coolerApply(async.map, passThrough), 
    coolerApply(async.map, passThrough), 
    coolerApply(async.sortBy, function(obj, callback){callback(null,obj)}) 
    ], 
    function(err, sorted){ 
    callback({"articles": sorted.reverse()}) 
    }) 
} 
//does the same thing as indexArticles! 
indexArticles2(console.log) 
1

यहाँ मैं अब तक के साथ समाप्त हो गया गया है।

function indexArticles(callback) { 
    var flow = [ 
    async.apply(fs.readdir, "posts/"), 

    function(data, callback) { async.map(data, readPost, callback); }, 

    function sortByDate(parsed, callback) { 
     var iterator = function(obj, callback) { 
     if (obj.date) { callback(null, obj.date); } 
     else { callback("Article has no date.") } 
     } 
     // Note that this sorts in reverse lexicographical order! 
     async.sortBy(parsed, iterator, 
      function(err, sorted) { callback(err, {"articles": sorted.reverse()}); } 
     ); 
    } 
    ]; 

    async.waterfall(flow, async.apply(callback)) 
} 
1

मैं हाल ही में सिंक मोड में async कार्यों कॉल करने के लिए WaitFor नाम के एक सरल अमूर्त (रेशे के आधार पर) बना लिया है: https://github.com/luciotato/waitfor

मैं async पैकेज के साथ यह परीक्षण नहीं किया है, लेकिन यह काम करना चाहिए । यदि आप समस्याओं में भाग लेते हैं, तो मुझसे संपर्क करें।

wait.for और का उपयोग async अपने कोड होगा:

var wait = require('waitfor'); 
var async = require('async'); 

function indexArticles(callback) { 
    var files = wait.for(fs.readdir,"posts/"); 
    var markdown = wait.for(async.map, files, readPost); 
    var results = wait.for(async.map, markdown, parse); 
    var sorted = wait.for(async.sortBy, results, function(obj, callback) { 
                callback(null, obj.date); 
               }); 
    callback(null, {"articles": sorted.reverse()}); 
} 

अपने fn (async-मोड) कॉल करने के लिए:

//execute in a fiber 
wait.launchFiber(indexArticles,function(err,data){ 
     // do something with err,data 
     }); 

अपने fn (सिंक मोड) कॉल करने के लिए:

//execute in a fiber 
function handleRequest(req,res){ 
    try{ 
     ... 
     data = wait.for(indexArticles); //call indexArticles and wait for results 
     // do something with data 
     res.end(data.toString()); 
    } 
    catch(err){ 
     // handle errors 
    } 
} 

// express framework 
app.get('/posts', function(req, res) { 
    // handle request in a Fiber, keep node spinning 
    wait.launchFiber(handleRequest,req,res); 
    }); 
संबंधित मुद्दे