2013-02-14 40 views
0

我簡直無法弄清楚這一點。我有一個文件夾。我想創建一個帶有這些文件信息的json。準確地說,文件名,文件名的正則表達式版本以及從ajax調用中獲得的附加數據。Javascript/NodeJs不同的異步函數導致一個大的JSON文件

個別部分完美工作。事實上,如果我同步運行我的代碼,我會得到我想要的結果。事情是這樣的:

[ 
      { 
       "filename" : "first file", 
       "regexname" : "first file", 
       "ajaxresult" : "first file" 
      }, 
      { 
       "filename" : "second file", 
       "regexname" : "second file", 
       "ajaxresult" : "second file" 
      }, 
] 

但我想這樣做異步,因爲XHR模塊我用不正常嘗試「同步」做的一切的時候,它的過程中有很多的文件,特別是阻斷。 我的「同步」的代碼看起來像這樣(有點簡化,使之更短)

fs.readdir(datapath, function(err, files) { 
    var data = new Array(); 
     if(err) throw err; 
     files.forEach(function(file){ 
      var filename = file 
      , regex= filename.replace(/regex/)/i, "") 
      , filepath = './public/config/dataconfig.js' 
      , ajaxResults = getFile(url) 
      , mapFiles = null 

     mapFiles = { filename:filename, regexname:regex, ajaxcall:ajaxResults} 
     data[data.length] = mapfiles; 
    } 
    var JSONdata= JSON.stringify(data, null, 4); 
    fs.writeFile(filepath, JSONdata, function(e) { 
     if (!e) { 
      console.log('Done') 
     }else{ 
      console.log('Failed', e) 
     }; 
    }); 
}); 

我想在一個承諾包裹AjaxCall的,但我失去了承諾內的文件名和regexname。像這樣:

fs.readdir(datapath, function(err, files) { 
    var data = new Array(); 
     if(err) throw err; 
     files.forEach(function(file){ 
      var filename = file 
      , regex= filename.replace(/regex/)/i, "") 
      , filepath = './public/config/dataconfig.js' 
      , mapFiles = null 

     // Make promise for async call with a url composed of the regex 
     var promise = getFile(url); 
     promise.then(function(result) { 
      mapFiles = { filename:filename, regexname:regex, ajaxcall:result} 
      data[data.length] = mapfiles; 
       var JSONdata= JSON.stringify(data, null, 4); 
       fs.writeFile(filepath, JSONdata, function(e) { 
        if (!e) { 
          console.log('Done') 
        }else{ 
          console.log('Failed', e) 
        }; 
        }); 
      }); 
    }); 

這給了我以下結果:

[ 
      { 
       "filename" : "first file", 
       "regexname" : "first file", 
       "ajaxresult" : "first file" 
      }, 
      { 
       "filename" : "first file", 
       "regexname" : "first file", 
       "ajaxresult" : "second file" 
      }, 
] 

所以我最終的想法是使用類似節點的異步模塊。在從函數獲取回調後寫入json。但我無法讓它工作。

在此先感謝!

[編輯 - 我忘了提及]

一件事我忘了提的是,AjaxCall的網址是建立與正則表達式。 因此,像這樣:

 url = 'http://www.test.com/'+regex 

所以這(在我看來),就意味着我做的正則表達式調用AjaxCall的面前,但我還需要正則表達式的電話後在JSON寫。我希望這是SENCE

[編輯2 - 有點更多信息]

我XHR調用看起來像這樣(沒有我的錯誤的諾言解決方案在這種情況下,我返回與結果的承諾。):

// Get info 
function getFile(url) { 
    xhr = new XMLHttpRequest(); 
    xhr.open("GET", url); 
    xhr.onreadystatechange = handler 
    var ajaxResult = null 
    //Callback 
    function handler(){ 
     // If status is ready 
     if (this.readyState == 4 && this.status == 200) { 
      ajaxResult = eval(this.responseText); 
      console.log('XHR OK') 
     }; 
    }; 
    xhr.send(null); 
    return ajaxResult[0]; 
}; 

回答

1

解決方案,這將正常工作,可能看起來像:

readdir(datapath).map(function (file) { 
    return getFile(url)(function (ajaxresult) { 
    return writeFile('./public/config/dataconfig.js', JSON.stringifiy({ 
     filename: file, 
     regexname: file.replace(/regex/i, ""), 
     ajaxcall: ajaxResult 
    }, null, 4)); 
    }); 
}).end(function() { 
    console.log("All done"); 
}, function (e) { 
    console.log("Failed", e); 
}); 

在這個例子中,我使用deferred承諾的實現,使之工作,你需要確保所有異步函數返回的承諾。典型的回調函數可以用deferred.promisify輕鬆轉換:

var promisify = require('deferred').promisify; 
var readdir = promisify(fs.readdir); 
var writeFile = promisify(fs.writeFile); 
+0

感謝您的回答。我想我只是沒有看到它,但是這給了我'失敗[TypeError:Caonnot讀屬性'0'null]。但我不明白它來自哪裏。 XHR調用給我正確的數據一次(這對我來說很奇怪)。 – jansmolders86 2013-02-15 11:24:40

+0

Vpml能夠完全顯示完整的錯誤堆棧跟蹤或代碼嗎? – 2013-02-15 13:57:10

+0

錯誤是由getFile引起的,它應該返回promise,但是它會嘗試從null屬性獲取索引(因此「無法讀取null屬性'0')。以下應該工作:http://jsfiddle.net/medikoo/BvQkJ/4/ – 2013-02-15 17:29:07

0

,如果你的問題越來越文件名和正則表達式,如何對他們結合到你的回調 像

var callback = function(result) { 
     mapFiles = { filename:this.filename, regexname:this.regex, ajaxcall:result} 
     data[data.length] = mapfiles; 
      var JSONdata= JSON.stringify(data, null, 4); 
      fs.writeFile(filepath, JSONdata, function(e) { 
       if (!e) { 
       console.log('Done') 
       }else{ 
        console.log('Failed', e) 
       }; 
       } 

然後

promise.then(callback.bind({'filename':filename,'regex':regex})) 
+0

你需要在node.js中使用promise嗎? – shargors 2013-02-14 20:41:34

+0

老實說我不知道​​,從來沒有用過 – srosh 2013-02-14 20:45:23

1

下面是使用async一個簡單的例子,如你所提到的:

doStuffWithFiles('folder', 'output.json', function() { 
    console.log('Done!'); 
}); 

function doStuffWithFiles (dirPath, outputFilePath, callback) { 
    fs.readdir(dirPath, function (error, files) { 
    async.map(
     files, 
     function (file, callback) { 
     doAjaxStuff(file, function (error, ajaxResults) { 
      callback(null, { 
      filename: file, 
      regexStuff: file.replace(/stuff/, ''), 
      ajaxResults: ajaxResults 
      }); 
     }); 
     }, 
     function (error, results) { 
     var data = JSON.stringify(results); 
     fs.writeFile(outputFilePath, data, function (error) { 
      callback(); 
     }); 
     } 
    ); 
    }); 
} 

的關鍵部分是async.map其作用類似於standard map function除了它需要你返回你的結果作爲參數傳遞給回調傳遞給你的第一個函數。一旦所有回調已經返回,async.map調用第二個函數,並將結果列表傳遞給它。根據承諾

+0

非常感謝這個答案。這幾乎正​​是我需要的。只有一件事我忘了提及; 'doAjaxStuff'使用url中的'regexStuff'。所以例如像這樣:url ='http://www.test.com/'+regexStuff。 doAjaxStuff函數將如下所示:getInfo(url,function(error,result)){ 我寧可不重複正則表達式兩次。再次感謝! – jansmolders86 2013-02-15 08:28:48