修复错误! (如何在同步函数中调用异步函数)
Fix the bug! (how to call an asynchronous function inside a synchronous function)
以下问题来自采访。我能够解决一些部分,但我卡住了:
修复以下代码中的错误。 DataContainer 是数据库的包装器,为从数据库中获取的数据提供缓存。
调用 fetch 应该通过 DbConnection 从数据库中获取数据。如果获取成功,它应该 return true;否则它应该 return false。调用 getData 应该 return 缓存数据或者如果数据还没有被获取则抛出异常。
function DataContainer(connectionString) {
var dataFetched = false;
var dbConnection = DbConnection(connectionString);
}
DataContainer.prototype.getData = function () {
if (!this.dataFetched)
throw "Data not fetched!";
return this.data;
}
DataContainer.prototype.fetch = function () {
this.dbConnection.getAllData(function (err, result) {
if (err) {
delete this.data;
this.dataFetched = false;
return false;
} else {
this.data = result;
this.dataFetched = true;
return true;
}
});
}
// Mock of DbConnection for testing purposes:
function DbConnection(connectionString) { }
DbConnection.prototype.getAllData = function (callback) {
callback(null, [1, 2, 3]);
}
//Expected: 1, 2, 3
var dc = new DataContainer('connection');
if (dc.fetch()) {
var data = dc.getData();
for (var i = 0; i < data.length; i++) {
console.log(data[i]);
}
}
我尽可能地修复了代码,包括在构造函数中创建新的 DbConnection 对象,使用 this 关键字定义属性var 在构造函数中,并在调用 getData 时将 this 绑定到回调函数(查看以下代码)。唯一剩下的问题是如何在同步函数中调用异步函数(getData)?!
function DataContainer(connectionString) {
this.dataFetched = false;
this.dbConnection = new DbConnection(connectionString);
}
DataContainer.prototype.getData = function () {
if (!this.dataFetched)
throw "Data not fetched!";
return this.data;
}
DataContainer.prototype.fetch = function () {
this.dbConnection.getAllData(function (err, result) {
if (err) {
delete this.data;
this.dataFetched = false;
return false;
} else {
this.data = result;
this.dataFetched = true;
return true;
}
}.bind(this));
}
fetch是一个同步函数,我们不允许让它变成异步的。 getData是一个异步函数,我们不允许让它同步。现在我们如何在 fetch 中使用 getData???
fetch
是同步的,但是 getAllData
是异步的,所以问题是如何让 getAllData
表现得像一个同步函数。实现此目的的一种(也可能是唯一的)方法是使用 async/await
:
DataContainer.prototype.fetch = async function fetch() {
return await new Promise(resolve => {
this.dbConnection.getAllData((err, result) => {
if (err) {
delete this.data;
this.dataFetched = false;
} else {
this.data = result;
this.dataFetched = true;
}
resolve(this.dataFetched);
});
});
}
这将允许消费代码将调用视为同步操作
以下问题来自采访。我能够解决一些部分,但我卡住了:
修复以下代码中的错误。 DataContainer 是数据库的包装器,为从数据库中获取的数据提供缓存。
调用 fetch 应该通过 DbConnection 从数据库中获取数据。如果获取成功,它应该 return true;否则它应该 return false。调用 getData 应该 return 缓存数据或者如果数据还没有被获取则抛出异常。
function DataContainer(connectionString) {
var dataFetched = false;
var dbConnection = DbConnection(connectionString);
}
DataContainer.prototype.getData = function () {
if (!this.dataFetched)
throw "Data not fetched!";
return this.data;
}
DataContainer.prototype.fetch = function () {
this.dbConnection.getAllData(function (err, result) {
if (err) {
delete this.data;
this.dataFetched = false;
return false;
} else {
this.data = result;
this.dataFetched = true;
return true;
}
});
}
// Mock of DbConnection for testing purposes:
function DbConnection(connectionString) { }
DbConnection.prototype.getAllData = function (callback) {
callback(null, [1, 2, 3]);
}
//Expected: 1, 2, 3
var dc = new DataContainer('connection');
if (dc.fetch()) {
var data = dc.getData();
for (var i = 0; i < data.length; i++) {
console.log(data[i]);
}
}
我尽可能地修复了代码,包括在构造函数中创建新的 DbConnection 对象,使用 this 关键字定义属性var 在构造函数中,并在调用 getData 时将 this 绑定到回调函数(查看以下代码)。唯一剩下的问题是如何在同步函数中调用异步函数(getData)?!
function DataContainer(connectionString) {
this.dataFetched = false;
this.dbConnection = new DbConnection(connectionString);
}
DataContainer.prototype.getData = function () {
if (!this.dataFetched)
throw "Data not fetched!";
return this.data;
}
DataContainer.prototype.fetch = function () {
this.dbConnection.getAllData(function (err, result) {
if (err) {
delete this.data;
this.dataFetched = false;
return false;
} else {
this.data = result;
this.dataFetched = true;
return true;
}
}.bind(this));
}
fetch是一个同步函数,我们不允许让它变成异步的。 getData是一个异步函数,我们不允许让它同步。现在我们如何在 fetch 中使用 getData???
fetch
是同步的,但是 getAllData
是异步的,所以问题是如何让 getAllData
表现得像一个同步函数。实现此目的的一种(也可能是唯一的)方法是使用 async/await
:
DataContainer.prototype.fetch = async function fetch() {
return await new Promise(resolve => {
this.dbConnection.getAllData((err, result) => {
if (err) {
delete this.data;
this.dataFetched = false;
} else {
this.data = result;
this.dataFetched = true;
}
resolve(this.dataFetched);
});
});
}
这将允许消费代码将调用视为同步操作