我一直在兑现promise和.then()的问题,我设法创建了两个promise并且它们运行了,但我认为,但是顺序仍然是错误的,第一个promise获取了一个更新的电子表格,而下一个promise填充到该电子表格并发送包含该工作表数据的邮件,无论我做什么,我都无法正确排序。邮件规则运行后,始终会显示“完成获取最新的驱动器工作表..”消息,但该消息应在此之前。 getNewSheet承诺应运行,然后sendMails承诺应运行。为什么不运行getNewSheet()然后再运行.sendMails?
请帮助我了解为什么它没有运行以及我对诺言做错了什么,另外,为什么诺言的消息方法不返回其值?我认为是因为承诺没有按正确的顺序解决。
请注意,我仍在学习和使用环境变量中的某些变量,我已经编辑了我能做的,有点长,但是我很好奇是否需要对每个promise中的包含代码/函数做进一步的事情会成功的。
已编辑:已编辑的代码更加准确。
let getNewSheet = function () {
return new Promise(function (resolve, reject) {
const fs = require("fs");
const readline = require("readline");
const {
google
} = require("googleapis");
const SCOPES = "https://www.googleapis.com/auth/drive";
const TOKEN_PATH = "token.json";
fs.readFile("credentials.json", (err, content) => {
if (err) return console.log("Error loading client secret file:", err);
authorize(JSON.parse(content), getLatestListFromDrive);
});
function authorize(credentials, callback) {
const {
client_secret, client_id, redirect_uris } = credentials.installed;
const oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[0]
);
fs.readFile(TOKEN_PATH, (err, token) => {
if (err) return getAccessToken(oAuth2Client, callback);
oAuth2Client.setCredentials(JSON.parse(token));
callback(oAuth2Client);
});
}
function getAccessToken(oAuth2Client, callback) {
const authUrl = oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: SCOPES
});
console.log("Authorize this app by visiting this url:", authUrl);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("Enter the code from that page here: ", code => {
rl.close();
oAuth2Client.getToken(code, (err, token) => {
if (err) return console.error("Error retrieving access token", err);
oAuth2Client.setCredentials(token);
fs.writeFile(TOKEN_PATH, JSON.stringify(token), err => {
if (err) console.error(err);
console.log("Token stored to", TOKEN_PATH);
});
callback(oAuth2Client);
});
});
}
function getLatestListFromDrive(auth) {
const drive = google.drive({
version: "v3",
auth
});
var fileId = process.env.NODE_DRIVE_FILE_ID;
var dest = fs.createWriteStream("" + appDir + "\\tmp\\feedbacklist.xlsx");
drive.files.export({
fileId: fileId,
mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}, {
responseType: "stream"
},
function (err, res) {
res.data
.on("end", () => {
})
.on("error", err => {
console.log("Error", err);
})
.pipe(dest);
}
);
}
resolve();
});
};
var path = require("path");
var appDir = path.dirname(require.main.filename);
let sendMails = function () {
return new Promise(function (resolve, reject) {
const XLSX = require("xlsx");
const workbook = XLSX.readFile("" + appDir + "\\tmp\\feedbacklist.xlsx", {
type: "binary",
cellDates: true,
dateNF: "yyyy-mm-dd;@"
});
const SheetNameList = workbook.SheetNames;
var rows = XLSX.utils.sheet_to_json(workbook.Sheets[SheetNameList[0]], {
raw: false
});
var raw = workbook.Sheets[SheetNameList[0]];
var today = new Date();
today = today.toISOString().slice(0, 10);
var dateYesterday = new Date();
dateYesterday.setDate(dateYesterday.getDate() - 1);
dateYesterday = dateYesterday.toISOString().slice(0, 10);
var dayYesterday = new Date();
var days = [
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
];
dayYesterday.setDate(dayYesterday.getDate() - 1);
dayYesterday = days[dayYesterday.getDay()];
var dateTomorrow = new Date();
dateTomorrow.setDate(dateTomorrow.getDate() + 1);
dateTomorrow = dateTomorrow.toISOString().slice(0, 10);
var dayTomorrow = new Date();
var futureDays = [
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
];
dayTomorrow.setDate(dayTomorrow.getDate() + 1);
dayTomorrow = futureDays[dayTomorrow.getDay()];
var filteredRows = rows.filter(eachRow);
function eachRow(eachRow) {
return eachRow["tourDate"] === dateYesterday;
}
if (filteredRows != 0) {
for (x = 0; x < filteredRows.length; x++) {
console.log(filteredRows[x].emailAddress);
console.log(filteredRows[x].fName);
console.log(filteredRows[x].tourDate);
console.log(filteredRows[x].feedbacksent);
var nodemailer = require("nodemailer");
var transporter = nodemailer.createTransport({
host: process.env.NODEMAILER_SERVICE,
secure: false,
auth: {
user: process.env.NODEMAILER_USER,
pass: process.env.NODEMAILER_PASS
}
});
var mailOptions = {
from: process.env.NODEMAILER_FROM,
to: "" + filteredRows[x].emailAddress + "",
subject: "Hi",
html: "Hi ",
text: "Hi "
};
console.log("I've sent a feedback request to " + filteredRows[x].emailAddress);
transporter.sendMail(mailOptions, function (error, info) {
//check for console errors
if (error) {
console.log(error);
} else {
console.log(
"Feedback request sent to " +
filteredRows[x].emailAddress
);
};
})
}
} else {
console.log("No rows/records to process for yesterday..");
}
resolve();
});
};
getNewSheet(console.log("drive fetched")).then(function (result) {
console.log("mails sent");
return sendMails(result);
}).then(function () {
console.log("promises finished");
});
答案 0 :(得分:2)
在您计划的操作实际上完成时,调用resolve
和reject
函数。
请记住,在处理异步操作时,您编写的代码是无序执行的,这意味着不是按照在文件中写入的顺序进行的。
考虑以下示例:
将无法正常工作
return new Promise(function (resolve, reject) {
let result
fs.someAsyncOperation(function (data) {
result = data
})
resolve(result) // the promise will resolve immediately with undefined value
}
会工作
return new Promise(function (resolve, reject) {
fs.someAsyncOperation(function (result) {
resolve(result) // the promise will resolve after async operation is completed
})
}
在调用resolve
函数之前,应重新编写代码以等待异步操作的结果。
答案 1 :(得分:2)
在sendMessage promise函数下,解析应该位于sendMail函数的回调中,因为它是异步的。
transporter.sendMail(mailOptions, function(error,info){
resolve();
});
异步内容有时会变得很棘手,特别是如果您习惯于同步流程。当我开始使用软件时,这让我感到困惑。
您保证功能会很好。那里的问题是您在实际完成发送功能之前就解决了它。
因此,下面是您的代码的简单版本。做同样的事情
// function that returns a message
// duration: 1s
function getMessage() {
return new Promise(resolve => {
setTimeout(() => resolve('important message'), 1000)
});
}
// function that send a message using sendEmail function
// duration should be based on sendEmail
// notice that the resolve is called inside the callback
function sendMessage(message) {
return new Promise((resolve, reject) => {
sendEmail(message, (err, result) => {
// do some stuff if email was sent
})
resolve();
});
}
// function try to send an email asynchronously using a callback
// duration: 0.5s
function sendEmail(message, callback) {
setTimeout(() => {
console.log('email sent!')
callback(null, 'message sent');
}, 500)
}
getMessage().then(result => {
return sendMessage(result);
}).then(() => {
console.log('should be done after email')
})
使用以上代码,您的终端应显示
should be done after email
email sent!
但是对sendMessage函数进行了一些修改
function sendMessage(message) {
return new Promise((resolve, reject) => {
sendEmail(message, (err, result) => {
resolve(result);
})
});
}
终端现在应该显示
email sent!
should be done after email