setInterval中的promise
我有这个例程函数在setInterval函数上每隔60000ms运行一次。在这个例程函数中,我遍历解析的JSON(db)上的所有用户名,并检查它们是否可通过promise(checkUsername)获得,这是一个网络请求。
但是,我很清楚这是一个糟糕的方法,因为承诺可能需要60多秒才能完成,而且我一直在收到ETIMEDOUT错误。但我只是不理解承诺和异步,足以想到一个解决方案。
什么是更好的方法呢? async / await适合吗?
function routine() {
db.users.forEach(userObj => {
userObj.username.forEach(username => {
checkUsername(username).then(hasUser => {
if(!hasUser) {
bot.sendMessage(userObj.chatId, `‼️ Username @${username} is now AVAILABLE ‼️`);
removeName(username, userObj.chatId);
}
}).catch(err => {
console.log(err);
})
})
});
}
setInterval(routine, 120000);
回答如下:
我创建了一个可以运行的代码片段,它使用Promise.all
以及async / await ES7来使代码更易于处理和理解。我也打算在网上找到一个真正的API端点,仅仅是为了一个完整的例子。
如果你想要那个选项,我还添加了一种方法来阻止超时。
// How often the timeout will run.
// Since the timeout is dependent on when all the requests finish, the timeout will run this many ms after all the requests finish.
var interval = 5000;
// This is what your db seems to resemble.
var db = {
users: [{
username: ['1']
},
{
username: ['2']
},
{
username: ['3']
},
{
username: ['4']
},
]
};
// This will hold the timeout function so you can cancel it at a later time.
var timeoutFn;
// Returns returns a single Promise that resolves when all of the promises it contains have resolved/rejected. It rejects with the first promise that rejects.
function routine() {
console.log("-- Running routine function --");
// Return an array of promises. Please see my comments at the bottom of this whole answer which questions db architecture with username being an array.
// I'm also using map instead of forEach because map automatically returns and array.
let promiseArray = db.users.map(userObj => {
return Promise.all(userObj.username.map(username => {
// This processUsername() function should do all the work related to the username. It helps to keep the routine function as clean as possible since there's already a lot happening in here.
return processUsername(username);
}));
});
// Returns an array of array of promises. This means that every single promise within each array (see above) has to resolve before the `then` runs. If any reject, `catch` will run instead.
return Promise.all(promiseArray).then(() => {
runRoutineAgain();
}).catch((err) => {
console.log('err:', err)
});
}
// This will create a timeout and run routine after interval.
function runRoutineAgain() {
timeoutFn = setTimeout(routine, interval);
}
// This async function returns a promise
async function processUsername(username) {
// Make API call to get data
console.log('Processing username for', username);
// I'm using this free API endpoint online just for the sake of making a complete example. Obviously your API will be returning very different data.
return await fetch(`https://jsonplaceholder.typicode/todos/${username}`)
.then(response => response.json())
.then((json) => {
console.log(json);
// This is where you can do your processing.
// if(!hasUser) {
// bot.sendMessage(userObj.chatId, `‼️ Username @${username} is now AVAILABLE ‼️`);
// removeName(username, userObj.chatId);
// }
});
}
function stopTimeout() {
clearTimeout(timeoutFn);
}
routine();
setInterval中的promise
我有这个例程函数在setInterval函数上每隔60000ms运行一次。在这个例程函数中,我遍历解析的JSON(db)上的所有用户名,并检查它们是否可通过promise(checkUsername)获得,这是一个网络请求。
但是,我很清楚这是一个糟糕的方法,因为承诺可能需要60多秒才能完成,而且我一直在收到ETIMEDOUT错误。但我只是不理解承诺和异步,足以想到一个解决方案。
什么是更好的方法呢? async / await适合吗?
function routine() {
db.users.forEach(userObj => {
userObj.username.forEach(username => {
checkUsername(username).then(hasUser => {
if(!hasUser) {
bot.sendMessage(userObj.chatId, `‼️ Username @${username} is now AVAILABLE ‼️`);
removeName(username, userObj.chatId);
}
}).catch(err => {
console.log(err);
})
})
});
}
setInterval(routine, 120000);
回答如下:
我创建了一个可以运行的代码片段,它使用Promise.all
以及async / await ES7来使代码更易于处理和理解。我也打算在网上找到一个真正的API端点,仅仅是为了一个完整的例子。
如果你想要那个选项,我还添加了一种方法来阻止超时。
// How often the timeout will run.
// Since the timeout is dependent on when all the requests finish, the timeout will run this many ms after all the requests finish.
var interval = 5000;
// This is what your db seems to resemble.
var db = {
users: [{
username: ['1']
},
{
username: ['2']
},
{
username: ['3']
},
{
username: ['4']
},
]
};
// This will hold the timeout function so you can cancel it at a later time.
var timeoutFn;
// Returns returns a single Promise that resolves when all of the promises it contains have resolved/rejected. It rejects with the first promise that rejects.
function routine() {
console.log("-- Running routine function --");
// Return an array of promises. Please see my comments at the bottom of this whole answer which questions db architecture with username being an array.
// I'm also using map instead of forEach because map automatically returns and array.
let promiseArray = db.users.map(userObj => {
return Promise.all(userObj.username.map(username => {
// This processUsername() function should do all the work related to the username. It helps to keep the routine function as clean as possible since there's already a lot happening in here.
return processUsername(username);
}));
});
// Returns an array of array of promises. This means that every single promise within each array (see above) has to resolve before the `then` runs. If any reject, `catch` will run instead.
return Promise.all(promiseArray).then(() => {
runRoutineAgain();
}).catch((err) => {
console.log('err:', err)
});
}
// This will create a timeout and run routine after interval.
function runRoutineAgain() {
timeoutFn = setTimeout(routine, interval);
}
// This async function returns a promise
async function processUsername(username) {
// Make API call to get data
console.log('Processing username for', username);
// I'm using this free API endpoint online just for the sake of making a complete example. Obviously your API will be returning very different data.
return await fetch(`https://jsonplaceholder.typicode/todos/${username}`)
.then(response => response.json())
.then((json) => {
console.log(json);
// This is where you can do your processing.
// if(!hasUser) {
// bot.sendMessage(userObj.chatId, `‼️ Username @${username} is now AVAILABLE ‼️`);
// removeName(username, userObj.chatId);
// }
});
}
function stopTimeout() {
clearTimeout(timeoutFn);
}
routine();