使用回调返回结果

时间:2017-08-25 19:15:32

标签: javascript node.js callback

我尝试查询数据库,然后从结果中创建一个对象数组,将它们转换为JSON对象。

我不熟悉Javascript的异步性质,我真的很困惑如何实现需要同步工作的东西。我知道我可能需要使用回调,但在看了很多教程之后我才会感到困惑。

这是没有回调的代码:



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

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

});
};

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

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




我尝试foreignTable(tablename, idArr, callback)使用回调调用queryForeignTable而没有运气。

有人可以解释一下如何让这段代码与回调一起使用吗?

2 个答案:

答案 0 :(得分: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.queryresults的结果异步回复,但您不能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函数中的某些值时,给函数一个回调参数,然后用你的返回值调用该回调。

您可以在此处运行代码:https://repl.it/K0YI/3

答案 1 :(得分:0)

当您进行异步调用时,如connection.query(statement, callback),那么无论您想对该调用的结果做什么,都需要在回调中完成。

请记住,异步函数不会返回您通常想要的最终值(通常它们会返回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范围内的变量,例如resultsArray和{ {1}}。

希望有所帮助。