gpt4 book ai didi

javascript - promise 未正确返回

转载 作者:行者123 更新时间:2023-12-03 07:20:45 25 4
gpt4 key购买 nike

我有以下功能。它反复调用自身并循环访问 ftp 服务器以检查新文件。我试图做出一个 promise ,以便我可以 operate().then(function(newFilesObject),但我无法获得 .then 操作激活。它确实尝试解决它,但不发送。顺便说一句,newFiles 是一个全局变量,它获取附加到它的每个服务器的文件。如果需要更多代码,我可以发布或 github 它。

function operate(){
return new Promise(function(resolve, reject){
if(servers[i]){
if(i!== 0) ftp = new JSFtp(servers[i].server)
local = servers[i].local
remote = servers[i].remote
localFiles = fs.readdirSync(local)
}else{
console.log('trying to resolve')
console.log(newFiles)
resolve(newFiles)
}
gatherFiles(remote).then(function(files){
if(files.length>0){
downloadNew(files).then(function(){
console.log('Done: ' + servers[i].server.host)
i++
operate()
})
}else{
console.log('No updates: ' + servers[i].server.host)
i++
operate()
}
})
})
}

operate().then(function(files){
console.log('files: ' + files)
})

最佳答案

代码示例中的 promise 不会返回,因为它们的解析器或拒绝器并不总是被调用。事实上,resolve 仅在 i === 0 时调用。根据Promises/A+ specification ,promise 只能通过调用 resolve 转换为 fulfilled 状态。它也只能通过调用 reject 或从执行器内部抛出异常来转换为 rejected 状态。因此,到达执行器末尾而不调用其中任何一个或将其作为回调传递可确保 Promise 无限期地保持在 pending 状态。

您寻求的目标可能通过一些重构来实现。将以下目标视为您的目标:

  1. 依次通过每个 FTP 服务器...
  2. 读取给定目录中的文件列表
  3. 将文件列表与本地存储的文件列表进行比较以确定新文件
  4. 如果有新的,请依次下载
  5. 返回所有新下载的文件的列表

数据

var knownFTPServers = [{
'localDirectory': 'sub/',
'localFilepaths': ['docA.json', 'docB.json'],
'remoteDirectory': 'remsub/',
'remoteFilepaths': [],
'jsftpHandle': undefined,
'host': 'example.com'
},
{
'localDirectory': 'root/',
'localFilepaths': ['file1.txt', 'file2.txt'],
'remoteDirectory': 'remroot/',
'remoteFilepaths': [],
'jsftpHandle': undefined,
'host': 'geocities.com'
}];

逻辑

function pullNewFilesFromFTPServer(ftpServer) {
return new Promise(function (resolve, reject) {
var handle = new JSFtp(ftpServer);
ftpServer.jsftpHandle = new JSFtp(ftpServer);

// Returns a promise for reading a directory from JSFtp server
// resolves with file list
// rejects with FTP error
function readdir(directory) {
return new Promise(function (resolve, reject) {
handle.ls(ftpServer.remoteDirectory, function (err, res) {
if (err) return reject(err);
resolve(res);
});
});
}

// Returns a promise for downloading a file from a remote JSFtp server
// resolves with the filepath of the downloaded filepath
// rejects with FTP error
function downloadFile(path) {
return new Promise(function (resolve, reject) {
handle.get(path, path, function (err) {
if (err) return reject(err);
resolve(path);
});
});
}

// get all remote filepaths on server
readdir(ftpServer.remoteDirectory)

// filter out filepaths already present locally
.then(function (remoteFilepaths) {
return remoteFilepaths.filter(function (path) {
return ftpServer.localFilepaths.indexOf(path) < 0;
});
})

// download new filepaths sequentially
// reduce turns the array of new filepaths into a promise chain
// return new filepaths after completing the promise chain
.then(function (newFilepaths) {
return newFilepaths.reduce(function (previousDownloadPromise, newPath) {
return previousDownloadPromise.then(function () {
return downloadFile(newPath);
});
}, Promise.resolve())
.then(function () { return newFilepaths; });
})

// resolve server promise with new filepaths or reject with errors
.then(resolve, reject);
});
}

var allFilesDownloaded = [];
knownFTPServers.reduce(function (previousServerPromise, server) {
return previousServerPromise.then(function (filesDownloaded) {
allFilesDownloaded = allFilesDownloaded.concat(filesDownloaded);
return pullNewFilesFromFTPServer(server);
});
}, Promise.resolve([]))

.then(function () {
console.log(allFilesDownloaded);
}, function (err) {
console.err(err);
});

虽然有些地方看起来有点复杂,但每个函数的操作都更加模块化。有点不直观的想法是使用 Array.prototype.reduce将数据数组转换为按顺序执行的 Promise 数组。

由于创建下载文件的 promise 会尝试立即下载该文件,因此如果您打算一次下载一个文件,则无法一次创建所有 promise 。否则,序列可能看起来更简单。

关于javascript - promise 未正确返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36225321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com