我正在尝试使用promise来确保设置某些属性,然后再尝试使用这些变量。
我已经设法编写了一些代码,这些代码似乎可以实现我想要的功能,但鉴于我对promise的了解,这些代码的顺序不符合我的期望。
创建Promise函数包装器(我认为)
function skillPromise(char, opts) {
return new Promise((res, rej) => {
skills_api.getCharactersCharacterIdSkills(char.eve_id, opts, (e, r, b) => {
if (!e) res(r.total_sp);
else rej(e);
});
});
}
使用诺言
characters.forEach((c) => {
skillPromise(c, opts).then((spt) => {
c.totalSP = spt;
console.log(spt);
console.log(c.totalSP);
}).catch(() => {});
});
console.log(characters);
输出
首次运行
[ { eve_id: 123456,
name: 'name',
access_token: '',
refresh_token: '' } ]
4652555
4652555
第二次运行
[ { eve_id: 123456,
name: 'name',
access_token: '',
refresh_token: '',
totalSP: 4652555
},
{ eve_id: 654321,
name: 'eman',
access_token: '',
refresh_token: '' } ]
9075602
9075602
所有后续运行将遵循该模式。
强制刷新与添加登录具有相同的效果,但是还会重新打印之前的值。
[ { eve_id: 123456,
name: 'name',
access_token:'',
refresh_token:'',
totalSP: 4652555 },
{ eve_id: 654321,
name: 'eman',
access_token:'',
refresh_token:'',
totalSP: 9075602 } ]
9075602
9075602
我想我只是不明白我在这里构造的东西。 主要是它的时机让我感到困惑。 为什么它按照我的期望却以不同的顺序执行?
编辑:
我完成了向API回调中添加promise函数包装器的工作,并使用Promise.all()
来解决它们,然后仅在then中呈现页面。基本上,它满足了我现在想要的。
使用诺言时我学到了两件事:
如果您有函数包装器,则实际上甚至可以在promise.all()
调用内向其传递参数
您仍然可以得到回报,但它们位于传递给.then()
全部承诺
Promise.all([skillPromise(c, opts), walletPromise(c, opts), locationPromise(c, opts)]).then((returns) => {
c.totalSP = returns[0];
c.walletBalance = returns[1];
c.solarSystem = returns[2];
res.render('characters', { characters: characters });
}).catch(() => {});
Promise函数包装器:
function skillPromise(char, opts) {
return new Promise((res, rej) => {
skills_api.getCharactersCharacterIdSkills(char.eve_id, opts, (e, r, b) => {
if (!e) res(r.total_sp);
else rej(e);
});
});
}
function walletPromise(char, opts) {
return new Promise((res, rej) => {
wallet_api.getCharactersCharacterIdWallet(char.eve_id, opts, (e, r, b) => {
if (!e) res(r);
else rej(e);
});
});
}
function locationPromise(char, opts) {
return new Promise((res, rej) => {
location_api.getCharactersCharacterIdLocation(char.eve_id, opts, (e, r, b) => {
if (!e) {
// Translate solar_system_id & station_id into System name and Station Name
universe_api.getUniverseSystemsSystemId(r.solar_system_id, opts, (e, r, b) => {
if (!e) res(r.name);
else rej(e);
});
} else rej(e);
});
});
}
答案 0 :(得分:0)
我认为这是正在发生的事情。
首先,您执行forEach
,forEach
的回调将对回调的每个调用(将被调用多次)将任务排队(待当前脚本完成后由事件循环执行)您在characters数组中具有的元素。将这些任务排队后,脚本的执行将继续执行console.log(characters);
,这是您首先看到的内容,现在脚本执行完成,事件循环将处理任务队列,处理forEach
添加的第一个任务(这是函数skillPromise
的一次执行,这会向微任务队列添加一个承诺。并且它为forEach
循环添加的每个任务执行此操作。如果在处理这些任务时某些承诺得到解决,则javascript将在处理forEach
排队的当前任务后处理它们(不是一个承诺,而是所有已解决的承诺)。如果在处理{{ 1}} javascript将在解决所有问题后对其进行处理。
顺序是,首先执行forEach
,然后处理任务和承诺。
您可以查看this视频,我发现它很好地解释了JavaScript事件循环的工作原理。
答案 1 :(得分:-1)
您可以使用.reduce()
函数包装上一个承诺的then()
中的每个承诺。
characters.reduce((prevPromise, c) => {
var promise = skillPromise(c, opts).then((spt) => {
c.totalSP = spt;
console.log(spt);
console.log(c.totalSP);
}).catch(() => {});
if(prevPromise == null){
return promise;
}else{
prevPromise.then(promise)
}
}, null);