Create and apply a reusable chain of promises onto other promises

268 Views Asked by At

Context:

I'm using node-horseman to web scrape. The situation is that after each action i make the headless browser take, i generally want to see the results.

The results can be seen by running

horseman
    .open('http://www.google.com')
    .html()
    .then((html)=>{
        return new Promise((resolve, reject)=>{
            console.log(html);
            fs.writeFile("result.html", html)
            resolve();
       })
    })
    .screenshot("result.png")
    .close();

Which creates writes the html to result.html and writes a screenshot of the rendered page to result.png.

Question:

instead of copy pasting that string of 4 promises, is it possible to assign that string of promises to a variable or method and then apply it? E.g.,

horseman
    .open('http://www.google.com')
    .preview_result()

Where

function preview_result(){
    return html()
        .then((html)=>{
            return new Promise((resolve, reject)=>{
                console.log(html);
                fs.writeFile("result.html", html)
                resolve();
           })
        })
        .screenshot("test.png")
        .close();
}

or

var preview_result = 
    html()
    .then((html)=>{
        return new Promise((resolve, reject)=>{
            console.log(html);
            fs.writeFile("result.html", html)
            resolve();
       })
    })
    .screenshot("test.png")
    .close();
2

There are 2 best solutions below

0
vsenko On BEST ANSWER

You can define a reusable function in such a way that it takes a Promise as an input:

function previewResult(openedUrl){
  return openedUrl
    .html()
    .then((html)=>{
      return new Promise((resolve, reject)=>{
        console.log(html);
        fs.writeFile("result.html", html, (error) => { // This way Promise will resolve only after the file was written
          if(error) {
            reject();
            return;
          }

          resolve();
        });
      })
    })
    .screenshot("test.png")
    .close();
}

This function will return something that was returned by close() function and if it was a Promise, you can simply continue a Promise chain.

You can use it this way:

const openedUrl = horseman.open('http://www.google.com');
previewResult(openedUrl)
  .then(() => { // Note that it will work only if close() returns a Promise
    console.log('all done!')
   });

Another approach is to use apply:

function previewResult(){
  return this
    .html()
    .then((html)=>{
      return new Promise((resolve, reject)=>{
        console.log(html);
        fs.writeFile("result.html", html, (error) => { // This way Promise will resolve only after the file was written
          if(error) {
            reject();
            return;
          }

          resolve();
        });
      })
    })
    .screenshot("test.png")
    .close();
}

const openedUrl = horseman.open('http://www.google.com');
previewResult.apply(openedUrl)
  .then(() => { // Note that it will work only if close() returns a Promise
    console.log('all done!')
   });

But I don't see any significant advantages in it.

0
Ulad Kasach On

I'm not sure how to do it with pure promises (which I will designate as the "accepted answer" when someone finds a solution) but...

node-horseman comes with the following functionality to create custom horseman promises

Horseman.registerAction('preview', function(results_path) {
  // The function will be called with the Horseman instance as this
  var self = this;
  // Return the horseman chain, or any Promise
  return this
    .html()
    .then((html)=>{
        return new Promise((resolve, reject)=>{
            console.log("html written");
            fs.writeFile(results_path+".html", html)
            resolve();
       })
    })
    .screenshot(results_path+".png")
});

Which results in the following doing as desired:

horseman
    .open('http://www.google.com')
    .preview()
    .close()

reference: https://github.com/johntitus/node-horseman

Their documentation rocks.