Я преобразовал все свои асинхронные обратные вызовы в обещания и, наконец, все заработало, теперь это кажется намного понятнее. Вот код для любого, кто спотыкается об этом:
Первая версия
ipcMain.on("moveFiles", (event, moveTo, moveFrom, databaseFile, doOverwrite, doRecursive, subFolder, doTestRun) => {
const db = new sqlite3.Database(databaseFile, sqlite3.OPEN_READONLY, (cErr) => {
if (cErr) {
console.error("Could not connect to the database");
throw cErr;
} else {
console.log("Connected to the database")
}
});
let query = `...`;
let regex = /.../;
const getAll = (query, params = []) => {
return new Promise((resolve, reject) => {
db.all(query, params, function (qErr, rows) {
if (qErr) {
console.error("Error running the query");
reject(qErr);
} else {
resolve(rows);
}
});
});
};
const getFiles = (path, type, options) => {
return new Promise((resolve, reject) => {
dir.files(path, type, function (fErr, files) {
if (fErr) {
console.error("Error iterating through files");
reject(fErr);
} else {
resolve(files);
}
}, options);
});
};
// Resolves to false if the file doesn't exist, true if it does
const checkFileExists = (path) => {
return new Promise(resolve => {
fs.access(path, fs.F_OK, function (aErr) {
if (aErr) {
resolve(false);
} else {
resolve(true);
}
});
});
};
getAll(query).then(async function (rows) {
let dbNameToFolder = {};
for await (const row of rows) {
dbNameToFolder[row["mediaType"]] = {
"local_folder": row["local_folder"],
"type": row["type"]
};
}
return dbNameToFolder;
}).then(function (assoc) {
getFiles(moveFrom, "file", {recursive: doRecursive}).then(async function (files) {
let filesToMove = [];
for await (const file of files) {
let filename = path.basename(file);
let matches = regex.exec(filename);
if (matches !== null && matches.length > 1 && assoc.hasOwnProperty(matches[2])) {
let newPath = path.join(moveTo, assoc[matches[2]]["type"], assoc[matches[2]]["local_folder"], subFolder, filename);
if (!doOverwrite) {
await checkFileExists(newPath).then(function(exists) {
if (!exists) {
console.log("Will move ", file, " to ", newPath);
filesToMove.push({
"oldPath": file,
"newPath": newPath
});
} else {
console.log("Moving ", file, " would overwrite ", newPath);
}
});
} else {
console.log("Will move ", file, " to ", newPath);
await filesToMove.push({
"oldPath": file,
"newPath": newPath
});
}
}
}
return filesToMove;
}).then(function(filesToMove) {
mainWindow.webContents.send("moveFilesResult", filesToMove);
if (doTestRun) {
console.log("Not moving files");
} else {
console.log("Moving files");
for (const file of filesToMove) {
(async () => {
await moveFile(file["oldPath"], file["newPath"], {
overwrite: doOverwrite
});
})();
}
}
});
});
});
Мне больше не нужен счетчик, я просто получаю длину массива в процессе рендеринга. Я правильно использую обещания и жду / asyn c сейчас?
Вторая версия
Это результат после переключения всего на await
. Я должен был сделать слушателя из ipcMain.on()
async
, чтобы иметь возможность await
. Может быть, лучше обернуть все мои await
вызовы в отдельный async
блок?
Я читал, что использование async
оборачивает функцию в Promise
, и мне нужно было использовать await
в функции convertPaths
для массива filesToMove
это хорошо?
Я также удалил await
на втором filesToMove.push()
, поскольку это казалось ненужным, но я не уверен.
Вы упомянули необходимость .catch()
, если я использую .then()
. Теперь, когда я не использую .then()
, как мне обрабатывать отклонения обещания, кроме как с .catch()
?
ipcMain.on("moveFiles", async (event, moveTo, moveFrom, databaseFile, doOverwrite, doRecursive, subFolder, doTestRun) => {
const db = new sqlite3.Database(databaseFile, sqlite3.OPEN_READONLY, (cErr) => {
if (cErr) {
console.error("Could not connect to the database");
throw cErr;
} else {
console.log("Connected to the database")
}
});
let query = `...`;
let regex = /.../;
const getAll = (query, params = []) => {
return new Promise((resolve, reject) => {
db.all(query, params, function (qErr, rows) {
if (qErr) {
console.error("Error running the query");
reject(qErr);
} else {
resolve(rows);
}
});
});
};
const getFiles = (path, type, options) => {
return new Promise((resolve, reject) => {
dir.files(path, type, function (fErr, files) {
if (fErr) {
console.error("Error iterating through files");
reject(fErr);
} else {
resolve(files);
}
}, options);
});
};
const convertPaths = async (assoc, files) => {
let filesToMove = [];
for (const file of files) {
let filename = path.basename(file);
let matches = regex.exec(filename);
if (matches !== null && matches.length > 1 && assoc.hasOwnProperty(matches[2])) {
let newPath = path.join(moveTo, assoc[matches[2]]["type"], assoc[matches[2]]["local_folder"], subFolder, filename);
if (!doOverwrite) {
await fs.promises.access(newPath, fs.constants.F_OK).then(() => console.log("Moving ", file, " would overwrite ", newPath)).catch(function () {
// If we catch an error, it's because the file doesn't exist, so we can move it without overwriting
console.log("Will move ", file, " to ", newPath);
filesToMove.push({
"oldPath": file,
"newPath": newPath
});
});
} else {
console.log("Will move ", file, " to ", newPath);
filesToMove.push({
"oldPath": file,
"newPath": newPath
});
}
}
}
return filesToMove;
};
let rows = await getAll(query);
let assoc = {};
for (const row of rows) {
assoc[row["mediaType"]] = {
"local_folder": row["local_folder"],
"type": row["type"]
};
}
let files = await getFiles(moveFrom, "file", { recursive: doRecursive });
let filesToMove = await convertPaths(assoc, files);
if (!doTestRun) {
for (const file of filesToMove) {
await moveFile(file["oldPath"], file["newPath"], { overwrite: doOverwrite });
}
console.log("Done moving files");
} else {
console.log("Not moving files");
}
mainWindow.webContents.send("moveFilesResult", filesToMove);
});
Третья версия
Я также сделал третья версия, где я удаляю (что я считаю) ненужные функции - и добавил Promise
для подключения к базе данных. Как это выглядит сейчас?
ipcMain.on("moveFiles", async (event, moveTo, moveFrom, databaseFile, doOverwrite, doRecursive, subFolder, doTestRun) => {
let query = `...`;
let regex = /.../;
const connect = (databaseFile, mode) => {
return new Promise((resolve, reject) => {
const db = new sqlite3.Database(databaseFile, mode, function (cErr) {
if (cErr) {
reject(cErr);
} else {
resolve(db);
}
});
});
};
const getAll = (db, query, params = []) => {
return new Promise((resolve, reject) => {
db.all(query, params, function (qErr, rows) {
if (qErr) {
console.error("Error running the query");
reject(qErr);
} else {
resolve(rows);
}
});
});
};
const getFiles = (path, type, options) => {
return new Promise((resolve, reject) => {
dir.files(path, type, function (fErr, files) {
if (fErr) {
console.error("Error iterating through files");
reject(fErr);
} else {
resolve(files);
}
}, options);
});
};
let db = await connect(databaseFile, sqlite3.OPEN_READONLY);
let rows = await getAll(db, query);
let assoc = {};
for (const row of rows) {
assoc[row["mediaType"]] = {
"local_folder": row["local_folder"],
"type": row["type"]
};
}
let files = await getFiles(moveFrom, "file", { recursive: doRecursive });
let filesToMove = [];
for (const file of files) {
let filename = path.basename(file);
let matches = regex.exec(filename);
if (matches === null || matches.length <= 1) continue;
if (!assoc.hasOwnProperty(matches[2])) continue;
let newPath = path.join(moveTo, assoc[matches[2]]["type"], assoc[matches[2]]["local_folder"], subFolder, filename);
if (!doOverwrite) {
await fs.promises.access(newPath, fs.constants.F_OK)
.then(() => console.log("Moving ", file, " would overwrite ", newPath))
.catch(function () {
// If we catch an error, it's because the file doesn't exist, so we can move it without overwriting
console.log("Will move ", file, " to ", newPath);
filesToMove.push({
"oldPath": file,
"newPath": newPath
});
});
} else {
console.log("Will move ", file, " to ", newPath);
filesToMove.push({
"oldPath": file,
"newPath": newPath
});
}
}
if (!doTestRun) {
for (const file of filesToMove) {
await moveFile(file["oldPath"], file["newPath"], { overwrite: doOverwrite }).catch(function(mErr) {
console.error(mErr);
});
}
console.log("Done moving files");
} else {
console.log("Not moving ", filesToMove.length, " files");
}
mainWindow.webContents.send("moveFilesResult", filesToMove);
});