2015-07-27 11 views
5

बहुत सारे डुप्लिकेट कोड लिखने के प्रयास में मैं कॉल खोलने की कोशिश नहीं कर रहा हूं। मैं अधिमानतः केवल शीर्ष स्तर से आसपास के कार्यों को पारित करना चाहता हूं। इस प्रकार सं.बिना खोलने के वादे लिखने के बाद

function ensureLink(srcPath, dstPath){ 
    dstPath = fsRedux.predictDir(srcPath, dstPath) 
    var dstDir = path.dirname(dstPath) 
    return fsRedux.exists(dstPath) 
    .then(_.partialRight(fsRedux.ifFalseThrow, false, new Error(dstPath+" exists cannot ensure link"))) 
    .then(_.bind(fsExtra.mkdirsAsync, fsExtra, dstDir)) 
    .then(_.bind(_.bind(fsExtra.linkAsync, fsExtra, srcPath, dstPath))) 
} 

हालांकि उपरोक्त कोड काम नहीं करता है। नीचे दिया गया परीक्षण दिखाता है कि आप boundpromisifyAll async फ़ंक्शन पास नहीं कर सकते हैं। इसका कारण यह है कि तत्कालीन मूल्य इन वादों में पारित किया जाता है जो उन्हें कॉल में अगली तर्क के रूप में कार्य करने का कारण बनता है, इन कार्यों के लिए इसका मतलब है कि वे कॉलबैक के रूप में आग लगते हैं, यही कारण है कि पहली टेस्ट त्रुटि Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test. के साथ मोचा में है।

var chai = require("chai") 
var chaiAsPromised = require("chai-as-promised") 
chai.use(chaiAsPromised) 
chai.should() 

var path = require("path") 
var _ = require("lodash") 
var mock = require("mock-fs") 

var Promise = require("bluebird") 
var fsRedux = require("./fs-redux") 
var fsExtra = Promise.promisifyAll(require("fs-extra")) 
var fs = Promise.promisifyAll(require("fs")) 

mock({ 
    'path/hello-alpha.txt': 'file content here', 
    'path/hello-beta.txt': 'file content here' 
}) 

var dstPath = "path/to/fake/dir/" 

function closedThen(srcPath, dstPath){ 
    dstPath = fsRedux.predictDir(srcPath, dstPath) 
    var dstDir = path.dirname(dstPath) 
    return fsRedux.exists(dstPath) 
    .then(_.partialRight(fsRedux.ifFalseThrow, false, new Error(dstPath+" exists cannot ensure link"))) 
    .then(_.bind(fsExtra.mkdirsAsync, fsExtra, dstDir)) 
    .then(_.bind(_.bind(fsExtra.linkAsync, fsExtra, srcPath, dstPath))) 
} 

function openThen(srcPath, dstPath){ 
    dstPath = fsRedux.predictDir(srcPath, dstPath) 
    var dstDir = path.dirname(dstPath) 
    return fsRedux.exists(dstPath) 
    .then(_.partialRight(fsRedux.ifFalseThrow, false, new Error(dstPath+" exists cannot ensure link"))) 
    .then(function(){ 
     return _.bind(fsExtra.mkdirsAsync, fsExtra, dstDir)() 
    }) 
    .then(function(){ 
     return _.bind(fsExtra.linkAsync, fsExtra, srcPath, dstPath)() 
    }) 
} 

describe("issue", function(){ 
    describe("closedThen()", function(){ 
    it("should return then and run promise", function(){ 
     return closedThen("path/hello-alpha.txt", dstPath).then(function(){ 
     return fsExtra.readFileAsync("path/to/fake/dir/hello-alpha.txt", "utf8").should.eventually.equal("file content here") 
     }) 
    }) 
    }) 
    describe("openThen()", function(){ 
    it("should return then and run promise", function(){ 
     return openThen("path/hello-beta.txt", dstPath).then(function(){ 
     return fsExtra.readFileAsync("path/to/fake/dir/hello-beta.txt", "utf8").should.eventually.equal("file content here") 
     }) 
    }) 
    }) 
}) 

क्या कार्य मौजूद हैं, या बाध्य कार्य को लपेटने का तरीका वादे के साथ काम करने की अनुमति देगा?

अद्यतन:

मैं समारोह रैपर (lodash उनमें से एक गुच्छा है) कि एक then या चलाने के लिए पारित करने के लिए partialing या binding from my question earlier या रैपिंग कार्यों के लिए एक आसान इंटरफेस के लिए अनुमति देने के सुइट का एक पुस्तकालय के लिए देख रहा हूँ Promise.reduce के भीतर। इस तरह चेनिंग वादे वास्तव में आसान हैं।

आदर्श रूप से मैं सिर्फ यह जानना चाहता हूं कि लाइन को कैसे काम करना है, इसे लपेटने का एक तरीका ताकि जब से इसका परिणाम पारित हो जाए तो यह अनदेखा हो जाता है। या एक अनुशंसित विकल्प।

.then(_.bind(fsExtra.mkdirsAsync, fsExtra, dstDir)) 
+4

वास्तव में यह समझना मुश्किल है कि आप क्या पूछ रहे हैं - क्या आप आगे स्पष्टीकरण दे सकते हैं। एक प्रोमोसिफाइड फ़ंक्शन (परिभाषा द्वारा कुछ हद तक) एक वादा देता है और अब कॉलबैक का उपयोग नहीं करता है। यदि आप इसे कॉल करते हैं, तो यह एक वादा वापस कर देगा जो केवल तभी हल किया जाता है जब अंतर्निहित एसिंक ऑपरेशन किया जाता है। इसके अतिरिक्त, यदि आप सीरियल ऑपरेशन चाहते हैं, समानांतर ऑपरेशन नहीं, तो आपको 'फ़ंक्शन' हैंडलर के फ़ंक्शन संदर्भ को पास करने की आवश्यकता है, न कि कुछ फ़ंक्शन निष्पादित करने का रिटर्न वैल्यू (जब तक कि रिटर्न वैल्यू स्वयं एक फ़ंक्शन नहीं है आप अनुक्रम में बुलाया जाना चाहते हैं)। – jfriend00

+2

हां, संपादन ने समस्या को समझने में बहुत मदद नहीं की।मिश्रित विभिन्न समस्याओं का एक गुच्छा विवरण है। मैं कम से कम देखता हूं 1. यूनिट टेस्ट ठीक से नहीं बनाया गया है और इसके परिणामस्वरूप एक समय समाप्त हो गया है (असफल दावा नहीं) 2. गलत तरीके से काम करता है कि कैसे 'बाइंड' काम करता है। वास्तव में उदाहरण के लिए आखिरी 'फिर' हैंडलर '_.bind (fsExtra.linkAsync ... 'श्रृंखला में पिछले वादे का परिणाम प्राप्त करता है। लेकिन' fsExtra.linkAsync' इसे तीसरे पैरामीटर के रूप में प्राप्त करता है (' dstPath' के बाद) –

+2

मैं अभी भी डॉन करता हूं अनुवर्ती नहीं हो सकता है। हो सकता है कि आप बस बैक अप ले सकें और उन विशिष्ट संचालनों का वर्णन कर सकें जिन्हें आप स्क्रिप्ट करना चाहते हैं और फिर पूछें कि इसे लिखने का सबसे प्रभावी तरीका कैसा है? ऐसा लगता है कि आप किसी प्रकार का सामान्य प्रश्न पूछने की कोशिश कर रहे हैं, लेकिन उपयोग कर रहे हैं समस्या का वर्णन करने के लिए बहुत से मुद्दों के साथ कोड का वास्तव में एक जटिल सेट है और आप हमें उस जटिलता में खो रहे हैं। क्या आप समस्या को एक बहुत ही सरल उदाहरण में कम कर सकते हैं? – jfriend00

उत्तर

0

यहां Ramda का उपयोग करके एक उदाहरण दिया गया है।

var Promise = require("bluebird") 
var R = require("ramda") 
var path = require("path") 
var fs = Promise.promisifyAll(require("fs")) 
var fse = Promise.promisifyAll(require("fs-extra")) 

function ifThrow(value, desiredValue, error){ 
    if(value == desiredValue) throw error 
    return value 
} 

var fsEnsureLink = function(srcpath, dstpath){ 
    return R.pipeP.apply(null, [ 
    R.always(fs.lstatAsync(srcpath).then(R.T, R.F)), 
    R.partialRight(ifThrow, false, new Error("source path does not exist")), 
    R.always(fs.lstatAsync(dstpath).then(R.T, R.F)), 
    R.partialRight(ifThrow, true, new Error("destination path exists")), 
    R.always(fse.mkdirsAsync(path.dirname(dstpath))), 
    R.always(fs.linkAsync(srcpath, dstpath)), 
    R.T, 
    ])() 
} 

fsEnsureLink("./package.json", "./test/package.json") 
// promise -> true || Error thrown 
0

यहां तीन कार्य हैं जो आपको केवल एक विधि के गहरे वादे लिखने की अनुमति देते हैं। वादे श्रृंखला के बाहर एक वैश्विक दायरे में ऑब्जेक्ट सेट को संपादित करने के लिए वे मॉड्यूल dotty का उपयोग करते हैं।

wrap के साथ आप वर्तमान में श्रृंखला में मूल्य को अनदेखा कर सकते हैं।

function wrap(fn){ 
    return function(){ 
    return fn() 
    } 
} 

exportResult के साथ आप बाद में उपयोग के लिए मूल्य स्टोर कर सकते हैं।

function exportResult(obj, property){ 
    return function(value){ 
    dotty.put(obj, property, value) 
    return value 
    } 
} 

provideResult के साथ आप अगले then कॉल पर वापस करने के लिए एक पिछले परिणाम मूल्य लौट सकते हैं।

function provideResult(obj, property){ 
    return function(){ 
    return dotty.get(obj, property) 
    } 
} 

इस तरह के कुछ में परिणाम।

function ensureLink(srcPath, dstPath){ 
    dstPath = fsRedux.predictDir(srcPath, dstPath) 
    var dstDir = path.dirname(dstPath) 
    var values = {} 
    return fsRedux.exists(dstPath) 
    .then(exportResult(values, "exists")) 
    .then(_.partialRight(fsRedux.ifFalseThrow, false, new Error(dstPath+" exists cannot ensure link"))) 
    .then(wrap(_.bind(fsExtra.mkdirsAsync, fsExtra, dstDir))) 
    .then(wrap(_.bind(fsExtra.linkAsync, fsExtra, srcPath, dstPath))) 
    .then(provideResult(values, "exists")) 
    // continue the chain provide result from exists... 
} 

मैं मूल रूप से इसके लिए एक और अधिक सुरुचिपूर्ण समाधान की तलाश में था। या मौजूदा मानक पर सिफारिशें जो यह करती हैं।

+0

आप शायद [रामदा] (http://ramdajs.com/) – Bergi

+0

पर एक नज़र डालना चाहते हैं, मुझे रामदा वास्तव में दिलचस्प लगता है लेकिन जटिल वादा श्रृंखला बनाने और नियंत्रण प्रवाह को प्रबंधित करने में मदद करने के लिए यह बहुत उपयोगी नहीं है। – ThomasReggi

+0

क्या आपने 'करीन', 'कंपोज़पी' पर एक नज़र डाली है? इसके अलावा 'nAry' का उपयोग करके आपका' रैप 'किया जा सकता है। – Bergi

संबंधित मुद्दे