2016-03-25 13 views
0

私は以下の機能を持っています。それは繰り返し呼び出され、新しいファイルをチェックするftpサーバーを反復します。私は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) 
}) 
+2

'()'の内部呼び出しを見てください。 Operateは約束を返しますが、何もしていません。 –

+0

これはまさに私が何を言っているのか理解していれば、私は再びサーバーを繰り返し処理できるからです。それが終わったら(最初にテストされているように)、それが解決されます。私はそれで何ができますか? note:https://github.com/dkran/FloorCoveringEDI/blob/combinator/app.js – dkran

+0

'if(servers [i])'が 'true'なら' resolve'を呼び出すことは決してありません。おそらく、内部の '操作()'呼び出しが返す約束が解決した後で解決したいと思うかもしれませんか? –

答えて

1

コードサンプルの約束は、リゾルバまたはリジェクトが常に呼び出されるわけではないため、返されません。実際には、resolveは、i === 0の場合にのみ呼び出されます。 Promises/A+ specificationによれば、約束は、resolveを呼び出すことによってfulfilled状態にのみ遷移することができる。 rejectを呼び出すか、エグゼキュータ内から例外をスローすることによってのみ、rejected状態に遷移することもできます。したがって、呼び出すことなくエグゼキュータの最後に到達するか、コールバックとして渡すことによって、約束は確実にpending状態にとどまります。

少しのリファクタリングで達成することができます。

  • ...各FTPサーバを介して

    1. 順次新しいもの
    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を使用して、データの配列を順次実行される約束事の配列に変えることです。

    ファイルのダウンロードを約束すると、すぐにファイルをダウンロードしようとするため、一度に1つずつダウンロードする予定がある場合、すぐにすべての約束を作成することはできません。それ以外の場合は、シーケンスがややシンプルに見えます。

    関連する問題