2017-01-25 36 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()返回的新諾言是包含checkWebpageForReferencetakeScreenshot兩個分辨率的對象。本質上,在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))); 

既然你是在服務器端,我強烈建議藍鳥作爲一個下拉更換爲原生的承諾。那麼你可以這樣做:

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

請注意,在每個步驟中都要等待所有事情的發生。最後映射第一個和Promise.all通常更快,允許所有步驟對每個文件並行運行。例如:'Promise.all(files.map(file => readfile(file).then(upload).then(delete).then(save)))。然後(d atas => ...) – jib