2017-07-26 130 views
1

我在Node中構建一個服務器,它將搜索文件夾以查看XML文件是否存在(glob),如果存在,請將文件(fs)作爲JSON對象(xml2js)讀取並最終將其存儲在一個數據庫的地方。我希望將解析器的結果輸出到另一個變量中,以便我可以對數據執行其他操作。據我所知,有些東西是同步運行的,但我無法弄清楚如何阻止它,並讓我等到它完成後繼續前進。如何從ES6中的解析器中獲取xml2js結果?

我從app.js分離出來我的功能到控制器的其他地方:

app.controller.js

const fs = require('fs-extra'); 
const glob = require('glob'); 
const xml2js = require('xml2js'); 

exports.requests = {}; 

exports.checkFileDrop = async() => { 
    console.log('Checking for xml in filedrop...'); 
    // this is the only place await works... 
    await glob('./filedrop/ALLREQUESTS-*.xml', (err, files) => { 
    var parser = new xml2js.Parser(); 
    // this is looking for a specific file now, which I'll address later once I can figure out this issue 
    fs.readFile('./filedrop/ALLREQUESTS-20170707.xml', 'utf16le', function (err, data) { 
     if (err) { 
     console.log('ERROR: ', err); 
     } else { 
     parser.parseString(data, (err, result) => { 
      if (err) { 
      console.log('ERROR: ', err); 
      } else { 
      console.log('data found'); 
      exports.requests = JSON.stringify(result.Records.Record); 
      // data is outputted here correctly 
      console.log(exports.requests); 
      // this doesn't even seem to want to save to exports.requests anyways... 
      } 
     }); 
     } 
    }); 
    }); 
} 

app.js

const appController = require('./controllers/app.controller'); 

// check if there is file in filedrop 
appController.checkFileDrop(); 
// prints out an empty object 
console.log(appController.requests); 
// can't do anything if it doesn't exist yet 
appController.saveToDB(appController.requests); 

回答

1

await將等待Promise值解析,否則它會j將它在承諾中給出的價值包裝起來並立即解決承諾。在你的榜樣,

await glob('./filedrop/ALLREQUESTS-*.xml', (err, files) => { 

調用glob不返回Promise,所以await基本上是無用的。所以你需要自己創造承諾。

exports.checkFileDrop = async() => { 
    console.log('Checking for xml in filedrop...'); 

    const files = await new Promise((resolve, reject) => glob('./filedrop/ALLREQUESTS-*.xml', (err, files) => { 
    if (err) reject(err); 
    else resolve(files); 
    }); 

    const parser = new xml2js.Parser(); 

    const data = await new Promise((resolve, reject) => fs.readFile('./filedrop/ALLREQUESTS-20170707.xml', 'utf16le', function (err, data) { 
    if (err) reject(err); 
    else resolve(data); 
    }); 

    const result = await new Promise((resolve, reject) => parser.parseString(data, (err, result) => { 
    if (err) reject(err); 
    else resolve(result); 
    }); 

    console.log('data found'); 

    const requests = JSON.stringify(result.Records.Record); 

    console.log(requests); 
} 

請注意,此函數現在將拒絕它返回的承諾,而不是強制記錄錯誤。

你也可以用助手來壓縮這個。例如,節點8包括util.promisify以使得這樣的代碼更容易寫入,例如,

const util = require('util'); 

exports.checkFileDrop = async() => { 
    console.log('Checking for xml in filedrop...'); 

    const files = await util.promisify(glob)('./filedrop/ALLREQUESTS-*.xml'); 
    const parser = new xml2js.Parser(); 

    const data = await util.promisify(fs.readFile)('./filedrop/ALLREQUESTS-20170707.xml', 'utf16le'); 

    const result = await util.promisify(parser.parseString.bind(parser))(data); 

    console.log('data found'); 

    const requests = JSON.stringify(result.Records.Record); 

    console.log(requests); 
} 
+0

所以現在我創建了這個函數的所有3個部分的承諾,我如何將'request'對象放入我的其他函數中,而不直接傳入它? – mikedloss

+0

你正在'返回請求;'然後無論你使用'checkFileDrop'你要麼'等待'它的結果,要麼做'.then'上的承諾獲得價值。 – loganfsmyth

+0

杜!我只是試了一下,仍然在不知不覺中使用我的exports.requests,這仍然給我一個空的對象。現在我只是使用'appController.checkFileDrop()。然後((數據)=> console.log(數據));'(用於測試),我得到了我想要的。非常感謝您的幫助!我迷路了,在功能後被埋在功能:) – mikedloss