2016-03-25 3 views
0

У меня есть следующая функция. Он вызывает себя повторно и выполняет итерации через ftp-серверы, проверяя наличие новых файлов. Я пытаюсь сделать это обещанием, чтобы я мог operate().then(function(newFilesObject), но я не могу получить .then для активации. Он пытается ее разрешить, но не передает. Кстати, newFiles - это глобальная переменная, которая получает файлы на каждый сервер, присоединенный к ней. Если требуется больше кода, я могу опубликовать его или опубликовать.Обещание не возвращается должным образом

+2

Посмотрите на внутренние вызовы 'operation()'. Операция возвращает обещание, но вы ничего не делаете с ним. –

+0

Это именно так, что я снова могу повторить сервер, если вы понимаете, что я говорю. если он закончился (как проверено в начале), он разрешает. Что я могу сделать с этим? note: https://github.com/dkran/FloorCoveringEDI/blob/combinator/app.js – dkran

+0

Давайте ставим его по-другому: если 'if (servers [i])' is 'true', вы никогда не вызываете' resolve'. Может быть, вы хотите решить после того, как обещание, возвращаемое внутренним вызовом 'operation()' разрешает? –

ответ

1

Обещания в образце кода не возвращаются, так как их резольверы или отклонители не всегда вызываются. Фактически, resolve вызывается только тогда, когда i === 0. Согласно Promises/A+ specification, обещания могут быть преобразованы только в состояние fulfilled путем вызова resolve. Он также может быть преобразован только в состояние rejected путем вызова reject или исключения исключения изнутри исполнителя. Таким образом, достижение конца исполнителя без вызова или передачи одного в качестве обратного вызова гарантирует, что обещание остается в 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' 
}]; 

Logic

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, чтобы превратить массив данных в массив обещаний, выполняемых последовательно.

С момента создания обещания загрузить файл пытается сразу загрузить файл, невозможно сразу же создать все обещания, если вы хотите загрузить их по одному. В противном случае последовательность может выглядеть несколько проще.

Смежные вопросы