2017-01-25 39 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