Javascript 如何创建异步代码?
嘿,所以我用Javascript 如何创建异步代码?,javascript,asynchronous,discord.js,Javascript,Asynchronous,Discord.js,嘿,所以我用discord.js为一个discord机器人制作排行榜,我想用用户名而不是ID来显示用户,所以使用discord.js我使用函数.fetchUser(ID) .fetchUser(ID)是一个承诺,它可能需要一些时间,具体取决于带宽 因此,因为discord.js使用了一个承诺,我的代码不再是异步的,我认为通过将代码放在一个承诺中,它将异步运行 我错了 我的代码: //This is ran inside a .prototype function so (this) is def
discord.js
为一个discord机器人制作排行榜,我想用用户名而不是ID来显示用户,所以使用discord.js
我使用函数.fetchUser(ID)
.fetchUser(ID)
是一个承诺,它可能需要一些时间,具体取决于带宽
因此,因为discord.js
使用了一个承诺,我的代码不再是异步的,我认为通过将代码放在一个承诺中,它将异步运行
我错了
我的代码:
//This is ran inside a .prototype function so (this) is defined
return new Promise((resolve, reject) => {
this.list = [];
//users is an object with user's IDs as the key
//Currently it only has one key in it (mine)
for (let i in users) {
let pos = 0;
let score = this.getScore(users[i]);
if (score === 0) {
client.fetchUser(i).then((user)=> {
console.log(`pushed`);//logs way after the "finish" is logged
this.list.push([user.username.substring(0,13), score])
});
continue;
}
for (let h = 0; h < this.list.length; h++) {
if (score >= this.list[h][1]) {
pos = h;
break;
}
}
client.fetchUser(users[i].id).then((user) => {
this.list.splice(pos, 0, [user.username.substring(0,13), score])
})
}
console.log(`Finished: `+this.list.length);
resolve(this.list);
})
//这是在.prototype函数中运行的,因此(This)是定义的
返回新承诺((解决、拒绝)=>{
this.list=[];
//用户是以用户ID为键的对象
//目前它只有一把钥匙(我的)
for(让我输入用户){
设pos=0;
让score=this.getScore(用户[i]);
如果(分数==0){
client.fetchUser(i).then((user)=>{
console.log(`pushed`);//在记录“finish”之后记录
this.list.push([user.username.substring(0,13),score])
});
继续;
}
for(设h=0;h=此列表[h][1]){
pos=h;
打破
}
}
client.fetchUser(用户[i].id).然后((用户)=>{
this.list.splice(pos,0,[user.username.substring(0,13),score])
})
}
log(`Finished:`+this.list.length);
解决(此列表);
})
你必须摆脱你收到的承诺。返回您正在等待但还不够的承诺。您必须向上传播Promise
s。如果你的函数调用链中的某个东西是异步的,那么你应该考虑整个链AycN.<
您可以从fetchUser(…)中填写this.list
。然后(…)
,这并不一定不好,只要您在fetchUser
的解析链完成之前不尝试使用list
。你没有那样做;您可以立即解析(此.list)
考虑一下原始函数的缩写形式:
return new Promise((resolve, reject) => {
this.list = [];
for (let i in users) {
// A promise is created right here
client.fetchUser(i).then((user) => {
// This will populate list AFTER the then callback
this.list.push([user.username.substring(0, 13), score])
});
}
// You aren't waiting until the promise created by fetchUser completes
resolve(this.list);
})
只有在所有相关用户都加载了他们的配置文件并检索了他们的分数后,才能将此.list
视为“完整”。考虑到这一点,我们可以使用Promise.all()
,它接受一个Promise
s数组,然后在所有提供的承诺都得到解决后进行解决。因此,要以这种方式等待,我们将执行类似的操作,这仍然不理想,但可以正确地等待:
return new Promise((resolve, reject) => {
this.list = [];
// This is an array of Promises
const discordUsersPromise = users.map(user => client.fetchUser(user));
// Wait till all the fetchUser calls are done
const listIsPopulatedPromise = Promise.all(discordUsersPromise).then(dUsers => {
// This replaces your for (let i in users) {}
Object.entries(users).forEach((user, idx) => {
const score = this.getScore(user);
const discordUser = dUsers[idx];
this.list.push([discordUser.username.substring(0, 13), score])
});
});
// We still have to wait for the list to be completely populated
return listIsPopulatedPromise.then(() => this.list);
})
考虑这个实现。我对您的代码做了一些假设,因为您使用了this。列出,但不包括this
的一个实例,但大部分应该是相同的:
/**
* Object to composite certain user properties
* @typedef {RealUser}
* @property {String} user The local string for the user
* @property {User} realUser The user that Discord gives us
* @property {Number} score The score this user has
*/
/**
* Class to encapsulate user and score and data
*/
class Game {
/**
* Constructs a game
*/
constructor() {
/**
* The users we are keeping score of
* @type {Object}
*/
this.users = {};
}
/**
* Get the score of a particular user
* @param {String} user User to get score of
* @returns {Number} User's score
*/
getScore(user) {
return this.users[user] || 0;
}
/**
* Get a composite of users and their status
* @param {String[]} users The users to put on our leaderboard
* @returns {Promise<RealUser[]>} Sorted list of users that we included in our leaderboard
*/
getLeaderBoard(users) {
// Map all the users that we are given to Promises returned bye fetchUser()
const allRealUsersPromise = Promise.all(users.map(user => client.fetchUser(user)
/*
* Create an object that will composite the string that we use
* to note the user locally, the Discord User Object, and the
* current score of the user that we are tracking locally
*/
.then(realUser => ({
user,
realUser,
score: this.getScore(user)
}))));
/*
* Once we have all the data we need to construct a leaderboard,
* we should sort the users by score, and hand back an array
* of RealUsers which should contain all the data we want to
* print a leaderboard
*/
return allRealUsersPromise
.then(scoredUsers => scoredUsers.sort((a, b) => a.score - b.score));
}
/**
* Prints out a leaderboard
* @param {String[]} users The users to include on our leaderboard
*/
printLeaderBoard(users) {
// Go get a leaderboard to print
this.getLeaderBoard(users).then(sortedScoredUsers => {
// Iterate our RealUsers
sortedScoredUsers.forEach((sortedScoredUser, idx) => {
const username = sortedScoredUser.realUser.username;
const score = sortedScoredUser.score;
// Print out their status
console.log(`${username.substring(0, 13)} is in position ${idx + 1} with ${score} points`);
});
});
}
}
const game = new Game();
game.users["bob"] = 5;
game.users["sue"] = 7;
game.users["tim"] = 3;
game.printLeaderBoard(Object.keys(game.users));
/**
*对象来组合某些用户属性
*@typedef{RealUser}
*@property{String}user用户的本地字符串
*@property{User}realUser Discord给我们的用户
*@property{Number}score此用户拥有的分数
*/
/**
*类来封装用户、分数和数据
*/
班级游戏{
/**
*构建一个游戏
*/
构造函数(){
/**
*我们正在记录的用户
*@type{Object}
*/
this.users={};
}
/**
*获取特定用户的分数
*@param{String}用户要获得的分数
*@返回{Number}用户的分数
*/
getScore(用户){
返回此。用户[用户]| | 0;
}
/**
*获取用户及其状态的组合
*@param{String[]}users将用户放在我们的排行榜上
*@returns{Promise}我们在排行榜中包含的已排序用户列表
*/
getLeaderBoard(用户){
//将我们获得的所有用户映射到fetchUser()返回的承诺
const allRealUsersPromise=Promise.all(users.map)(user=>client.fetchUser(user)
/*
*创建一个将合成我们使用的字符串的对象
*要在本地注意用户,请注意Discord用户对象和
*我们正在本地跟踪的用户的当前分数
*/
.then(realUser=>({
用户,
realUser,
分数:this.getScore(用户)
}))));
/*
*一旦我们获得了构建排行榜所需的所有数据,
*我们应该按分数对用户进行排序,并返回一个数组
*包含我们想要的所有数据的RealUsers
*打印排行榜
*/
返回allRealUsersPromise
然后(scoredUsers=>scoredUsers.sort((a,b)=>a.score-b.score));
}
/**
*打印出排行榜
*@param{String[]}用户要包括在我们排行榜上的用户
*/
打印排行榜(用户){
//去打印排行榜吧
这个.GetLeadboard(用户)。然后(sortedScoredUsers=>{
//迭代我们的真实用户
sortedScoredUsers.forEach((sortedScoredUsers,idx)=>{
const username=sortedScoredUser.realUser.username;
const score=sortedScoredUser.score;
//打印出他们的状态
log(`${username.substring(0,13)}位于${idx+1}位置,有${score}点`);
});
});
}
}
const game=新游戏();
游戏用户[“bob”]=5;
游戏用户[“sue”]=7;
游戏用户[“tim”]=3;
打印排行榜(Object.keys(game.users));
您需要链接您的承诺。查看函数“Promise.all”以获取承诺列表(例如,var-onepromise=client.fetchUser(i);
-将它们添加到列表中),并创建一个承诺,该承诺将生成一个响应值列表。您可能不需要显式地使用newp