承诺未按预期解决
Promises not resolving as expected
我很难思考如何实现我的承诺。在我的主代码块中,我使用:
this.services.city.get(this.game.player.id, this.game.player.realm).then((cities) => {
console.log('core', cities);
}).catch((err) => console.log(err));
以及我的城市服务中的获取方法:
get(owner, realm){
var _t = this;
return new Promise(function(resolve, reject){
var cities = [];
var query = 'SELECT * FROM cities WHERE owner = '+owner+' AND realm = '+realm;
_t.core.db.query(query).then((results) => {
for(var i = 0; i < results.length; i++){
var data = {
id: results[i].id,
name: results[i].name,
owner: results[i].owner,
age: results[i].age,
x: results[i].x,
y: results[i].y,
realm: results[i].realm,
food: results[i].food,
wood: results[i].wood,
stone: results[i].stone,
ore: results[i].ore,
gold: results[i].gold,
population: results[i].population,
buildings: {}
};
var city = CityModel(data);
Promise.all([_t.getCurrentBuilds(city.id), _t.getCityBuildings(city.id), _t.getFieldBuildings(city.id)]).then((values) => {
city.currentBuilds = values[0];
city.buildings.city = values[1];
city.buildings.field = values[2];
console.log('city', city);
cities.push(city);
});
}
resolve(cities);
}).catch((err) => {
reject(err);
});
});
}
console.log('city', city);
的输出显示了我需要的数据,但是,console.log('core', cities);
是一个空数组。在解析整个城市数组之前,我如何才能等待 get 方法的循环完成以及其他 promises 解析?
在调用 resolve(cities)
之前,您没有等待 Promise.all()
完成。这里有很多错误。您正在使用反模式将所有这些包装在另一个手动创建的承诺中(您可以只使用已经拥有的承诺)并且您需要将 Promise.all()
链接到父级承诺。并且,您需要将循环承诺累积在一个数组中并对它们使用 Promise.all()
。或者,更改为顺序实现并使用 async/await
.
这是修复后的版本:
get(owner, realm) {
const _t = this;
const query = 'SELECT * FROM cities WHERE owner = ' + owner + ' AND realm = ' + realm;
return _t.core.db.query(query).then((results) => {
const promises = [];
for (let result of results) {
const data = {
id: result.id,
name: result.name,
owner: result.owner,
age: result.age,
x: result.x,
y: result.y,
realm: result.realm,
food: result.food,
wood: result.wood,
stone: result.stone,
ore: result.ore,
gold: result.gold,
population: result.population,
buildings: {}
};
const city = CityModel(data);
const p = Promise.all([
_t.getCurrentBuilds(city.id),
_t.getCityBuildings(city.id),
_t.getFieldBuildings(city.id)
]).then((values) => {
city.currentBuilds = values[0];
city.buildings.city = values[1];
city.buildings.field = values[2];
console.log('city', city);
return city;
});
promises.push(p);
}
// collect all the city objects from their promises
return Promise.all(promises);
});
}
由于我无法 run/test 此代码,因此此处可能存在一些拼写错误,但希望您能看到核心结构并进行必要的修复。
主要变化:
- Return 函数中的顶级承诺并将其他所有内容链接到它上面,以消除将现有承诺包装在手动创建的承诺中的反模式。除了使异步流程正常工作之外,您的代码还缺少各种无法将错误传播回调用者的错误处理路径。
- 将
for
循环中 Promise.all()
的结果收集到一个数组中,这样我们就可以在该数组上使用 Promise.all()
来知道什么时候一切都完成了。
- 在内部
Promise.all()
中执行 return city
以便它成为该承诺的解析值,我们可以将其作为 Promise.all()
结果的一部分按顺序进行跟踪,而不是将其推入更高范围的数组。
- 添加
Promise.all()
以跟踪 for
循环的结果并从 .then()
处理程序中收集所有城市和 return 以链接它。
- 处处摆脱
var
。你不应该再用 var
编程了。 const
和 let
在现代 Javascript. 更合适
这里有一个更简单的版本,它使用了一些 async/await
,但仍然保留了各个城市查询的并行执行:
async get(owner, realm) {
const _t = this;
const query = 'SELECT * FROM cities WHERE owner = ' + owner + ' AND realm = ' + realm;
const results = await _t.core.db.query(query);
return Promise.all(results.map(async result => {
const data = {
id: result.id,
name: result.name,
owner: result.owner,
age: result.age,
x: result.x,
y: result.y,
realm: result.realm,
food: result.food,
wood: result.wood,
stone: result.stone,
ore: result.ore,
gold: result.gold,
population: result.population,
buildings: {}
};
const city = CityModel(data);
const values = await Promise.all([
_t.getCurrentBuilds(city.id),
_t.getCityBuildings(city.id),
_t.getFieldBuildings(city.id)
]);
city.currentBuilds = values[0];
city.buildings.city = values[1];
city.buildings.field = values[2];
console.log('city', city);
return city;
});
}
我很难思考如何实现我的承诺。在我的主代码块中,我使用:
this.services.city.get(this.game.player.id, this.game.player.realm).then((cities) => {
console.log('core', cities);
}).catch((err) => console.log(err));
以及我的城市服务中的获取方法:
get(owner, realm){
var _t = this;
return new Promise(function(resolve, reject){
var cities = [];
var query = 'SELECT * FROM cities WHERE owner = '+owner+' AND realm = '+realm;
_t.core.db.query(query).then((results) => {
for(var i = 0; i < results.length; i++){
var data = {
id: results[i].id,
name: results[i].name,
owner: results[i].owner,
age: results[i].age,
x: results[i].x,
y: results[i].y,
realm: results[i].realm,
food: results[i].food,
wood: results[i].wood,
stone: results[i].stone,
ore: results[i].ore,
gold: results[i].gold,
population: results[i].population,
buildings: {}
};
var city = CityModel(data);
Promise.all([_t.getCurrentBuilds(city.id), _t.getCityBuildings(city.id), _t.getFieldBuildings(city.id)]).then((values) => {
city.currentBuilds = values[0];
city.buildings.city = values[1];
city.buildings.field = values[2];
console.log('city', city);
cities.push(city);
});
}
resolve(cities);
}).catch((err) => {
reject(err);
});
});
}
console.log('city', city);
的输出显示了我需要的数据,但是,console.log('core', cities);
是一个空数组。在解析整个城市数组之前,我如何才能等待 get 方法的循环完成以及其他 promises 解析?
在调用 resolve(cities)
之前,您没有等待 Promise.all()
完成。这里有很多错误。您正在使用反模式将所有这些包装在另一个手动创建的承诺中(您可以只使用已经拥有的承诺)并且您需要将 Promise.all()
链接到父级承诺。并且,您需要将循环承诺累积在一个数组中并对它们使用 Promise.all()
。或者,更改为顺序实现并使用 async/await
.
这是修复后的版本:
get(owner, realm) {
const _t = this;
const query = 'SELECT * FROM cities WHERE owner = ' + owner + ' AND realm = ' + realm;
return _t.core.db.query(query).then((results) => {
const promises = [];
for (let result of results) {
const data = {
id: result.id,
name: result.name,
owner: result.owner,
age: result.age,
x: result.x,
y: result.y,
realm: result.realm,
food: result.food,
wood: result.wood,
stone: result.stone,
ore: result.ore,
gold: result.gold,
population: result.population,
buildings: {}
};
const city = CityModel(data);
const p = Promise.all([
_t.getCurrentBuilds(city.id),
_t.getCityBuildings(city.id),
_t.getFieldBuildings(city.id)
]).then((values) => {
city.currentBuilds = values[0];
city.buildings.city = values[1];
city.buildings.field = values[2];
console.log('city', city);
return city;
});
promises.push(p);
}
// collect all the city objects from their promises
return Promise.all(promises);
});
}
由于我无法 run/test 此代码,因此此处可能存在一些拼写错误,但希望您能看到核心结构并进行必要的修复。
主要变化:
- Return 函数中的顶级承诺并将其他所有内容链接到它上面,以消除将现有承诺包装在手动创建的承诺中的反模式。除了使异步流程正常工作之外,您的代码还缺少各种无法将错误传播回调用者的错误处理路径。
- 将
for
循环中Promise.all()
的结果收集到一个数组中,这样我们就可以在该数组上使用Promise.all()
来知道什么时候一切都完成了。 - 在内部
Promise.all()
中执行return city
以便它成为该承诺的解析值,我们可以将其作为Promise.all()
结果的一部分按顺序进行跟踪,而不是将其推入更高范围的数组。 - 添加
Promise.all()
以跟踪for
循环的结果并从.then()
处理程序中收集所有城市和 return 以链接它。 - 处处摆脱
var
。你不应该再用var
编程了。const
和let
在现代 Javascript. 更合适
这里有一个更简单的版本,它使用了一些 async/await
,但仍然保留了各个城市查询的并行执行:
async get(owner, realm) {
const _t = this;
const query = 'SELECT * FROM cities WHERE owner = ' + owner + ' AND realm = ' + realm;
const results = await _t.core.db.query(query);
return Promise.all(results.map(async result => {
const data = {
id: result.id,
name: result.name,
owner: result.owner,
age: result.age,
x: result.x,
y: result.y,
realm: result.realm,
food: result.food,
wood: result.wood,
stone: result.stone,
ore: result.ore,
gold: result.gold,
population: result.population,
buildings: {}
};
const city = CityModel(data);
const values = await Promise.all([
_t.getCurrentBuilds(city.id),
_t.getCityBuildings(city.id),
_t.getFieldBuildings(city.id)
]);
city.currentBuilds = values[0];
city.buildings.city = values[1];
city.buildings.field = values[2];
console.log('city', city);
return city;
});
}