2017-01-25 4 views
1

У меня есть куча функций, которые возвращают обещания, которые я хочу сделать обобщенное, и поэтому я их пишу так:Модульные обещания и Promise.all()

function checkWebpageForReference(data){ 
    //checks a webpage for the reference in html 
    var promise = new Promise(function(resolve,reject){ 
     fetchUrl(data.url, function(err, meta, body){ 
      if (err) { reject(err); } else { 
       console.log(body) 
       if (body.toString().indexOf(data.text) !== -1){ 
        resolve(data); 
       } else { 
        reject("Could not find quote"); 
       } 
      } 
     }); 
    }); 
    return promise; 
} 

function takeScreenshot(data){ 
    //takes a screenshot of a webpage and saves it to the file system 
    //TODO: Mouse coordinates 
    data.id = shortid.generate(); 
    data.filename = data.id+'.png'; 
    var promise = new Promise(function(resolve,reject){ 
     webshot(data.url, data.filename, { shotOffset: {left: data.mouseX, top: data.mouseY} }, function(err) { 
      if (err) { reject(err); } else { 
       resolve(data); 
      } 
     }); 
    }); 
    return promise; 
} 

function uploadReferencePictureToS3(data){ 
    //uploads a picture to S3 
    var promise = new Promise(function(resolve, reject){ 
     s3.putObject({ 
      ACL: 'public-read', 
      Bucket: S3_BUCKET, 
      Key: data.id, 
      Body: data.picturedata, 
      ContentType: "image/jpg" 
     }, function(err) { 
      if (err) { reject(err); } else { 
       resolve(data); 
      } 
     }); 
    }); 
    return promise; 
} 

function saveNewReferenceToDb(data){ 
    //saves a new Reference to the database 
    var promise = new Promise(function(resolve, reject){ 
     new Reference({ 
      _id: data.id, 
      url: data.url, 
      text: data.text, 
      screenshot_url: AWS_S3_URL + data.id, 
      created_by: "Daniel" 
     }).save(function(err, saved){ 
      if (err) { reject(err); } else { 
       data.newReference = saved; 
       resolve(data); 
      } 
     }); 
    }); 
    return promise; 
} 

function readFile(data){ 
    //reads a file from the file structure and stores it in a variable 
    var promise = new Promise(function(resolve,reject){ 
     console.log(data); 
     fs.readFile(data.filename, function(err, picturedata){ 
      console.log(picturedata); 
      if (err) { reject(err); } else { 
       data.picturedata = picturedata; 
       resolve(data); 
      } 
     }) ; 
    }); 
    return promise; 
} 

function deleteFile(data){ 
    //deletes a file from the file structure 
    var promise = new Promise(function(resolve, reject){ 
     fs.unlink(data.filename); 
     resolve(data); 
    }); 
    return promise; 
} 

постановляю данных в каждой функции, потому что я планируют иметь много этих типов функций, и я не знаю порядок они будут называться в то время как цепочки:

readfile(somedata) 
.then(upload) 
.then(delete) 
.then(save) 
//etc 

Это работает отлично, пока я не должен делать Promise.all:

Promise.all([ 
     referenceTools.checkWebpageForReference(req.body), 
     referenceTools.takeScreenshot(req.body) 
    ]) 
    .then(function(results){ 
     utils.readFile(results[1]) 
     .then(referenceTools.uploadReferencePictureToS3) 
     .then(utils.deleteFile) 
     .then(referenceTools.saveNewReferenceToDb) 
     .then(function(data){ 
      res.json(data.newReference); 
     }) 
     .catch(function(err){ 
      utils.errorHandler(err); 
      res.send("There was an internal error. Please try again soon."); 
     }); 
    }) 
    .catch(function(err){ 
     utils.errorHandler(err); 
     res.send("There was an internal error. Please try again soon."); 
    }); 
    //my very ugly way of doing it 

Использование Promise.all().then(upload) дает мне ошибки, потому что новое обещание, возвращенное Promise.all(), является объектом, который содержит оба разрешения от checkWebpageForReference и takeScreenshot. По существу, в readFile я не могу получить доступ к полям data, потому что итоговое обещание - [data, data].

Есть ли образец, который я могу выполнить, чтобы помочь мне достичь того, что мне нужно сделать? Мне нужно сделать обещания модульными, предоставляя им как можно больше данных.

+0

Итак, выполняйте ли каждая из ваших функций некоторый общий интерфейс? т. е. 'prf1' и' prf2' возвращают объекты, содержащие 'new_variable1'? Если нет, как вы можете сделать 'prf3' последовательным, если он не знает, что он получает? –

+0

@MattWay На самом деле их нет. Я оставлял это до их использования во время цепочки. Я понимаю, что он подвержен ошибкам, но мне еще предстоит выяснить, как это сделать. Функции просто предполагают, что 'data' содержит поле, которое они запрашивают. Если цепь спроектирована хорошо, тогда они будут. Но я не уверен, как это стандартизировать. – db2791

+0

Можете ли вы привести пример того, что вы хотите, чтобы 'prf3' выглядел внутренне? –

ответ

0

Вы можете .map() над ними, как так:

Promise.all(...) 
    .then(datas => Promise.all(datas.map(upload))); 

Поскольку вы на стороне сервера, я настоятельно рекомендую Bluebird как дроп-ин для замены родных Promises. Тогда вы можете сделать:

Promise.all(...) 
    .map(upload); 
+1

Остерегайтесь, что это ждет всего, что можно догнать на каждом шагу. Как правило, быстрее сначала сопоставлять, а Promise.all last, позволяя всем шагам запускаться параллельно для каждого файла. Например: 'Promise.all (files.map (file => readfile (файл). Then (upload). Then (удалить). Then (save))), затем (d atas => ...)' – jib

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