情況:
我有一個在代碼開頭運行的函式load_content:
async function load_content() {
console.log("I GOT HERE 1");
await load_js_files("./cmds/","commands")
console.log("I GOT HERE 2");
await load_js_files("./events/","events");
}
此函式呼叫load_js_files兩次,load_js_files是一個遞回函式,它為指定目錄中的每個目錄呼叫自身,“要求”找到的每個檔案并在 或 時執行不同的type = commands操作type = events。
該函式load_js_files如下所示:
function load_js_files(dir,type){
fs.readdir(dir, (e, files) => {
if(e) console.error(e);
let jsfiles = files.filter(f => f.split(".").pop() === "js");
if(jsfiles.length <= 0){
console.log(`No commands to load from ${dir}!`);
return;
}
for(const file of files){
if(fs.lstatSync(dir file).isDirectory()){
load_js_files(dir file "/",type)
}
}
if(type === "commands"){
console.log("\x1b[4m%s\x1b[0m",`Loading ${jsfiles.length} commands from ${dir} ...`);
jsfiles.forEach((f,i) => {
let command = require(`${dir}${f}`);
console.log(`${i 1}: ${f} loaded!`);
bot.commands.set(command.info.name, command);
});
} else if (type === "events"){
console.log("\x1b[4m%s\x1b[0m",`Loading ${jsfiles.length} events from ${dir} ...`);
jsfiles.forEach((f,i) => {
let event = require(`${dir}${f}`);
console.log(`${i 1}: ${f} loaded!`);
let commands = [];
for(const cmd of bot.commands){
if(cmd[1].data) commands.push(cmd[1].data.toJSON());
}
if(event.once){
bot.once(event.name, (...args) => event.execute(...args, commands));
} else {
bot.on(event.name, (...args) => event.execute(...args, commands));
}
});
} else {
console.log(log_Red,"FUNCTION 'load_js_files' CALLED WITH INCORRECT 'type'.")
}
});
return new Promise((resolve,reject) => resolve("DONE"));
}
我希望load_content事件按以下順序發生:
控制臺日志
I GOT HERE 1load_js_files與commands引數一起發生(當然我還沒有解決遞回承諾,但它應該至少運行一次)控制臺日志
I GOT HERE 2load_js_files再次發生但帶有events引數。
問題:
運行時load_js_files要求type = event變數 ( bot.commands) 未定義。在通話bot.commands期間,根據上面的步驟 2 分配值。load_js_files
From what I can debug to, the initial function load_content does not respect (my understanding) of async/await, so I assume I am doing something incorrectly with promises.
In my console however the two console.log statements execute immidiatley & before the function is finished:
I GOT HERE 1
I GOT HERE 2
Loading 3 commands from ./cmds/ ...
1: createtables.js loaded!
2: ping.js loaded!
3: sqltest.js loaded!
Loading 1 events from ./events/ ...
1: ready.js loaded!
Loading 1 commands from ./cmds/settings/ ...
1: set.js loaded!
What I've tried:
I've tried the code noted above, additionally I have tried wrapping the second run of load_js_files in a .then(), I've tried a callback function & I've also tried nesting Promises but run into issues as load_js_files is calling itself recursively.
I'm having a hard time understanding if these Promises are going to work with this type of recursion (all recursions of load_js_files must finish before the second load_js_files is called within load_content).
Bonus points:
Bonus points if you can help me understand promises within a recursive function. I've read
- https://blog.scottlogic.com/2017/09/14/asynchronous-recursion.html
- https://www.bennadel.com/blog/3201-exploring-recursive-promises-in-javascript.htm and
- https://medium.com/@wrj111/recursive-promises-in-nodejs-769d0e4c0cf9
But it's not quite getting through.
Attempt at implementing David's answer:
This results in error, I believe related to fs.readdir(dir) requiring a callback.
Error: TypeError [ERR_INVALID_CALLBACK]: Callback must be a function. Received undefined
async function load_js_files_async_test(dir,type){
const files = fs.readdir(dir);
for (const file of files) {
const file_info = await lstat(dir file);
if(file_info.isDirectory()){
await load_jsfiles_async_test(dir file "/", type);
} else {
console.log("Thanks David!");
}
}
}
uj5u.com熱心網友回復:
不尊重/不等待承諾
當然可以。這是它正在等待的 Promise:
new Promise((resolve,reject) => resolve("DONE"))
當然,這個 Promise 完成得非常快(并且是同步的),然后代碼繼續執行下一個任務。但是代碼中任何地方都沒有等待的是這個異步操作:
fs.readdir(dir, (e, files) => {
//...
});
這個呼叫readdir是一個異步操作,因此直到當前執行緒完成它正在做的所有事情之后才會呼叫回呼函式。其中包括正在等待的“承諾”(不做任何異步操作)以及console.log陳述句和下一次呼叫load_js_files.
幸運的是,Node 也提供了這些操作的基于 Promise 的版本。
稍微簡化一下原始代碼,想象一下這個結構:
async function load_js_files(dir, type) {
const files = await readdir(dir);
for (const file of files) {
const fileInfo = await lstat(dir file);
if(fileInfo.isDirectory()) {
await load_js_files(dir file "/", type)
}
}
// etc.
}
如您所見,這“讀取”更像是同步操作。這里的想法是洗掉回呼函式的使用,這本質上會導致您感到困惑并使“等待”變得更加困難。現在函式中的所有邏輯load_js_files都直接在load_js_files函式中,而不是在其他匿名回呼函式中。并且該邏輯逐步進行,等待每個異步操作。
然后你可以按預期await呼叫。load_js_files
uj5u.com熱心網友回復:
功能
fs.readdir
是一個非阻塞函式,這意味著您插入的代碼不會被“等待”完成,您可以嘗試使用fs.readdirSync并洗掉您的return new Promise().
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/448901.html
