Вышеупомянутый скрипт велик. Я использовал следующие команды для загрузки файлов, а также для вывода вывода в файл, который полезен при отладке, и это распространенное заблуждение, что windows ftp не может выполнять пассивный режим, чтобы команда пассивная была " quote pasv "(я добавил это в скрипт
Sub FtpFileto()
Set FSO = CreateObject("scripting.filesystemobject")
F = "C:\FTPScript.txt"
' Create the ftpscript to be run
Open F For Output As #1
Print #1, "open ftp.server.com" 'replace ftp.server with the server address
Print #1, "ID" 'login id here
Print #1, "PWD" 'login password here
Print #1, "quote pasv" ' passive mode ftp if needed
Print #1, "cd " & " /dir" 'Directory of file location
Print #1, "cd " & " subdir" 'Sub-Directory of file location
Print #1, "ascii"
Print #1, "prompt"
'Put the file from the host and save it to the specified directory and filename
Print #1, "put " & VREDET; """C:\file1.csv"""; ""
Print #1, "put " & VREDET; """C:\file2.csv"""; ""
Print #1, "put " & VREDET; """C:\file3.csv"""; ""
Print #1, "disconnect" 'disconnect the session
Print #1, "bye"
Print #1, "exit"
Close #1
'Now for the command to upload to the ftpsite and log it to a text file
' the trick is to use the standard command shell which allows logging
Shell "cmd /c C:\WINDOWS\system32\ftp.exe -i -s:C:\FTPScript.txt > c:\ftpuploadlog.txt", vbHide
End Sub
Как уже говорилось, вы должны избегать использования метода обратного вызова при работе с асинхронными операциями на итерациях из-за их сложности.
(Вы можете пропустить этот раздел, если не хотите знать мотивацию подхода к обещаниям).
Просто отметим, что при подходе с обратным вызовом вы должны ждать завершения всех обратных вызовов в вашем getThumbUrls()
, используя if
, который проверит, были ли вызваны все обратные вызовы, а затем просто вызвать callback(thumbUrls);
с все ответы помещаются в ваш массив thumbUrls
:
function getThumbUrls(contentIndex, callback) {
const thumbUrls = [];
// counter which will increment by one for every callback
let counter = 0;
JSON.parse(contentIndex).forEach(videoKey => {
getThumbFileName(videoKey, function (thumbFileName) {
thumbUrls.push(CLOUDFRONT_URL + videoKey + '/thumbnails/' + thumbFileName);
// for each callback response you must add 1 to a counter and then
counter++;
// check if all callbacks already has been called
if (counter === JSON.parse(contentIndex).length) {
// right here, thumbsUrls are filled with all responses
callback(thumbUrls);
}
});
});
}
Итак, вы можете использовать обещания, и вам будет достаточно Promise.all
для обработки всех ответов от API. Вы можете учиться через Интернет и проверить код ниже, который использует подход обещания. Я добавил несколько комментариев, чтобы помочь вам понять, что происходит.
// when using promises, no callbacks is needed
getThumbUrls(contentIndex)
.then(function (data) {
console.log('Returning from getThumbUrls');
// let's just display thumbUrls[0] for now...
console.log('The thumbUrls are ' + data[0]);
})
// when using promises, no callbacks is needed
function getThumbUrls(contentIndex) {
console.log('Entering getThumbUrls');
// not needed anymore, Promise.all will return all values
// var thumbUrls = [];
// Promise.all receives an array of promises and returns to next .then() all results
// changing forEach to map to return promises to my Promise.all
return Promise.all(JSON.parse(contentIndex).map(videoKey => {
console.log('videoKey = ' + videoKey);
// returning a promise
return getThumbFileName(videoKey)
.then(function (thumbFileName) {
console.log('Returning from getThumbFileName');
console.log('Returned thumb filename is ' + thumbFileName);
return CLOUDFRONT_URL + videoKey + '/thumbnails/' + thumbFileName;
});
}))
}
// when using promises, no callbacks is needed
function getThumbFileName(videoKey) {
console.log('Entering getThumbFileName...');
const s3 = new AWS.S3({
apiVersion: '2006-03-01',
params: {
Bucket: 'my-bucket-name'
}
});
// Get the name of the file.
params = {
Bucket: 'my-bucket-name',
Delimiter: '/',
Prefix: videoKey + '/' + THUMBS_FOLDER,
MaxKeys: 1
};
// urlKey not need anymore
// var urlKey;
// most of AWS functions has a .promise() method which returns a promise instead calling callback funcions
return s3.listObjectsV2(params).promise()
.then(function (data) {
var thumbsKey = data.Contents;
//if you want to return only first one thumbsKey:
return thumbsKey[0];
})
.catch(function (err) {
console.log(err, err.stack);
callback(err);
return;
})
}
Надеюсь, это поможет вам в учебе.
Может кто-нибудь показать мне, как заставить исполнение ждать
blockquote>Это неправильный вопрос. Вы не пытаетесь заставить казнить «ждать» или, по крайней мере, не должны этого делать. Вам просто нужно вызвать обратный вызов в нужном месте - внутри обратного вызова из
s3.listObjectsV2()
, а не снаружи.function getThumbFileName(videoKey, callback) { ... s3.listObjectsV2(params, (err, data) => { if (err) { ... } var thumbsKey = data.Contents; // MaxKeys was 1 bc first thumbnail key is good enough for now. Therefore, only one iteration. thumbsKey.forEach(function (keys) { console.log('thumbKey = ' + keys.Key); urlKey = keys.Key; }); callback(urlKey); // right }); // wrong // callback(urlKey); }
Как вы написали, обратный вызов срабатывает после того, как
s3.getObjectsV2()
начинает работать , а не после того, как завершает (вызывает собственный обратный вызов).