M
M
Michael2019-01-17 13:07:54
Node.js
Michael, 2019-01-17 13:07:54

How to make Node.js promise chaining work correctly?

Good afternoon! I'm trying to understand the basics of asynchronous development for Node.js. The task that I came up with for myself looks like this: download the page to a specific address, then save it, then parse and select the desired part according to the template (classes in the html code), and save the selected piece into a separate file.
The code looks like this:

var rp = require('request-promise');
var fs = require('fs-extra'); // расширенный модуль для работы с файловой системой

let a = rp('https://somesite.com/')
    .then((htmlString) => {
        let path = './saved.html';
        fs.outputFile(path, htmlString);
    })
    .then(() => console.log('HTML saved to file!')) // до этого момента отрабатывает нормально
    .then(() => {
        fs.readFile('./saved.html', 'utf8', function (error, data) {
            if (error) {
                console.log(error)
            }
            let start = data.indexOf('<div class="some-class">');
            let finish = data.indexOf('<script class="some-another-class">');
            console.log(start); // для отладки смотрю, нашлись ли вхождения
            console.log(finish);

            let htmlSubstring = data.substring(start, finish);
            console.log(htmlSubstring.length); //смотрю, вырезалась ли нужная мне часть html
            let parsed = './parsed.html';
            fs.outputFile(parsed, htmlSubstring);
        })
    })
    .then(() => console.log('HTML (parsed) saved to file!'))
    .catch((err) => console.error(err));

However, the code does not work correctly: on the first run, when the saved.html file has not yet been created, everything crashes at the stage of reading it:
{ [Error: ENOENT: no such file or directory, open 'D:\git\tests\saved.html']
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: 'D:\\git\\tests\\saved.html' }
D:\git\tests\index.js:15
            let start = data.indexOf('<div class="some-class">');
                             ^

TypeError: Cannot read property 'indexOf' of undefined
    at ReadFileContext.<anonymous> (D:\git\tests\index.js:15:30)
    at ReadFileContext.callback (D:\git\tests\node_modules\graceful-fs\graceful-fs.js:90:16)
    at FSReqCallback.readFileAfterOpen [as oncomplete] (fs.js:244:13)
Program exited with status code of 1.

On the second run, when the file has already been downloaded, the code works, but the output still looks different than it should:
HTML saved to file!
HTML (parsed) saved to file!
25447
40883
15436
Program exited with status code of 0.

First, the message from the lower promise is displayed, and only then - from the upper one.
Why is it so? After all, in theory, the chain should be executed like this: the new .then() takes effect only when the previous one has completely worked out. And it turns out for me that they work in parallel, and it is clear that the output to the console works faster, and file operations are slower.
I ask you not to kick much, asynchronous code in JS is not easy for me.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
V
Vladimir Skibin, 2019-01-17
@nyakove

return fs.outputFile(path, htmlString);
You are working with asynchrony, and each next promise must start after the current one. Also wrap fs.readFile in return new Promise() so that the final console.log works correctly

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question