2017-01-25 4 views
1

ich eine Reihe von Funktionen, die Versprechen zurück, die ich verallgemeinert machen wollen, und so schreibe ich sie wie folgt aus:Modular Versprechungen und 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; 
} 

ich in jedem Funktionsdaten lösen, weil ich planen eine Menge von diesen Arten von Funktionen zu haben, und ich weiß nicht, den Auftrag werden sie gerufen werden, während Verkettungs:

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

das funktioniert gut, bis ich Promise.all zu tun haben:

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 

Die Verwendung von Promise.all().then(upload) gibt mir Fehler, weil die neue Versprechen von Promise.all() ist ein Objekt, das beide Auflösungen von checkWebpageForReference und takeScreenshot enthält. Im Wesentlichen, in readFile, kann ich nicht auf data Felder zugreifen, weil das resultierende Versprechen [data, data] ist.

Gibt es ein Muster, dem ich folgen kann, um mir zu helfen, das zu erreichen, was ich tun muss? Ich muss die Versprechen machen, ihnen so viele Daten wie möglich zur Verfügung zu stellen.

+0

Also, folgen Sie jeder Ihrer Funktionen einige gemeinsame Schnittstelle? d.h. 'prf1' und' prf2' geben beide Objekte zurück, die 'new_variable1' enthalten? Wenn nicht, wie kann man 'prf3' konsistent machen, wenn es nicht weiß, was es empfängt? –

+0

@MattWay Es gibt nicht wirklich ein Muster, dem sie folgen. Das habe ich bei der Verkettung ihrer Verwendung überlassen. Ich weiß, dass das fehleranfällig ist, aber ich muss noch einen besseren Weg finden. Die Funktionen nehmen nur an, dass "data" ein Feld enthält, nach dem sie fragen. Wenn die Kette gut entworfen ist, dann werden sie es tun. Aber ich bin mir nicht sicher, wie ich das standardisieren soll. – db2791

+0

Können Sie ein Beispiel dafür geben, wie "prf3" intern aussehen könnte? –

Antwort

0

können Sie .map() über sie wie so:

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

Da Sie auf der Server-Seite sind, dann empfehle ich Drossel als Drop-in-Ersatz für native Promises hoch. Dann können Sie tun:

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

Vorsicht, es wartet darauf, dass bei jedem Schritt alles aufholt. Es ist in der Regel schneller zuerst und Promise.all zuletzt zu mappen, so dass alle Schritte parallel für jede Datei ausgeführt werden können. Beispiel: 'Promise.all (files.map (file => readfile (datei)) .dann (upload) .dann (delete) .dann (save))). Then (d atas => ...)' – jib

Verwandte Themen