2017-08-25 150 views
0

我想查詢一個數據庫,然後從結果中創建一個對象數組,將它們變成一個JSON對象。用回調返回結果

我不習慣Javascript的異步性,我真的很困惑如何實現需要同步工作的東西。我知道我可能需要使用回調,但在看了很多教程後,我只剩下更多的困惑。

這是不進行回調的代碼:

var foreignTable = (tablename,idArr)=>{ 
 
\t var dataArray = []; 
 
\t //call a query for each of the ids 
 
\t var objectToAdd; 
 
\t for(var id of idArr){ 
 
\t \t objectToAdd = queryForeignTable(tablename,id); 
 
\t \t dataArray.push(objectToAdd); 
 
\t } 
 
\t return dataArray; 
 
\t 
 
connection.end(); 
 
}; 
 

 
var queryForeignTable = (tablename,id)=>{ 
 
\t connection.query("SELECT * FROM "+tablename+" WHERE id="+id, function (error, results, fields) { 
 
\t if(error)throw error; 
 
\t var objectToAddToArray={}; 
 
\t //Go through each field in a result and make the object 
 
\t for(packet of fields){ 
 
\t \t var label = packet.name; 
 
\t \t objectToAddToArray[label] = results[0][label]; 
 
\t } 
 
\t 
 
\t return objectToAddToArray; 
 

 
}); 
 
}; 
 

 
var arrayOfDrivers = foreignTable("driver",[1,2]); 
 
    
 
outputJson["drive"]=arrayOfDrivers; 
 

 
console.log(outputJson); // { drive: [ undefined, undefined ] }

我試圖foreignTable(tablename, idArr, callback)有回調調用queryForeignTable沒有運氣。

有人可以解釋我怎麼可以得到這段代碼與回調工作?

+1

也許你想檢查* ES7的異步功能(異步/等待)*。例如。這[介紹](http://rossboucher.com/await/) – oneturkmen

+0

learnyounode是一個很好的教程,如果你還沒有嘗試過https://github.com/workshopper/learnyounode –

回答

0

回調函數是一個作爲參數傳遞給另一個函數的函數,然後在外函數內調用該函數來完成某種例程或動作。

MDN: Callback function

回調是講述一個功能下一步做什麼,如「大功告成後,運行該功能」的一種方式。

例如:

first = function (callback) { 
    console.log("First!"); 
    callback(); 
} 

second = function() { 
    console.log("Second!"); 
} 

first(second); 

會產生:

First! 
Second! 

您也可以使用匿名函數產品相同的結果:

first(function() { 
    console.log("Second!") 
}); 

關於從你的問題的具體例子,你是正確的,你需要使用回調有點不同。您不需要在兩個函數中使用return語句,而需要使用回調函數。 connection.query與您的結果異步返回爲results,但您不能將return轉換爲您的queryForeignTable函數。而是給queryForeignTable一個回調函數來運行。您的foreignTable函數也有同樣的想法。

我沒有連接到數據庫,很明顯,所以我掐滅一個數據庫連接和簡化你想要做什麼,但它應該是這個樣子:

// Stubbed DB connection 
var connection = {}; 
connection.query = (id, cb) => { 
    var results = [ 
    { 
     id: id, 
     name: 'Name of ' + id, 
    }, 
    ]; 
    cb(null, results); 
}; 

var foreignTable = (ids, cb) => { 
    var data = []; 
    for (var i = 0; i < ids.length; i++) { 
    queryForeignTable(ids[i], (error, obj) => { 
     data.push(obj); 
     if (i == ids.length - 1) { 
     cb(null, data); 
     } 
    }); 
    } 
}; 

var queryForeignTable = (id, cb) => { 
    connection.query(id, (error, results) => { 
    if (error) { 
     cb(error, null); 
    } 
    cb(null, results[0]); 
    }); 
}; 

foreignTable([1, 2], (error, data) => { 
    if (error) { 
    console.error(error); 
    } 
    console.log(data); 
}); 

產生:

[ { id: 1, name: 'Name of 1' }, { id: 2, name: 'Name of 2' } ] 

從本質上說,當你有一種衝動,return在異步方式的函數一些值(S),給函數的回調參數,然後調用你的返回值該回調。

您可以運行此代碼:當你有一個異步調用,就像connection.query(statement, callback)https://repl.it/K0YI/3

0

,那麼無論你想與調用的結果,這樣做需要在回調中完成。

請記住,異步函數不會返回您通常想要的最終值(通常它們會返回undefined)。而不是使用返回值,而是通過回調來表達,「當你完成時,繼續並結果做這件事」,又如。延續傳球風格。

您代碼中的一個挑戰是您要爲每個ID分別發出查詢,然後將結果彙總到一個響應數組中。這意味着您需要檢查所有查詢何時完成,然後才能顯示最終結果。

下面是您的示例,重新編寫,評論和簡化。希望這有助於解釋控制流程如何工作。

// Read row IDs 1 and 2 from the "driver" table. 
readTable("driver", [1, 2], displayData); 

// Print the results. 
function displayData (arrayOfDrivers) { 
    console.log(arrayOfDrivers); 
} 

// Read all rows matching IDs in `idArray` from `tableName`, 
// put results into an array, and finally invoke `callback`. 
function readTable (tablename, idArray, callback) { 
    var resultsArray = []; 

    // Queue up all the async queries. 
    for (var id of idArray){ 
     queryTable(table, id, handleResponse); 
    } 

    // A query finished, so handle the result. 
    function handleResponse (error, results, fields) { 
     if (error) { 
      throw error; 
     } 

     // Add the query result to array of results. 
     resultsArray.push(results[0]); 

     // Check if all queries are done. 
     if (resultsArray.length === idArray.length) { 
      // Invoke the callback with the resultsArray. 
      // The callback is in fact the `displayData` function. 
      callback(resultsArray); 
     } 
    } 
} 

// Execute a query, using the `cb` callback to handle the response. 
function queryForeignTable (tablename, id, cb) { 
    var query = "SELECT * FROM " + tablename + " WHERE id=" + id; 
    connection.query(query, cb); 
} 

注意,handleResponse函數在readTable功能的範圍內定義的,所以它可以在readTable適適用範圍訪問的變量,如resultsArraycallback

希望有所幫助。