nyakove
@nyakove

Как заставить цепочку промисов в Node.js работать правильно?

Добрый день! Пытаюсь разобраться в основах асинхронной разработки под Node.js. Задача, которую я себе придумал, выглядит так: выкачать страницу по определенному адресу, затем сохранить ее, после этого распарсить и выделить нужную часть по шаблону (классы в html-коде), а выделенный кусок сохранить в отдельный файл.

Код выглядит так:

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));


Однако код работает неправильно: при первом прогоне, когда файл saved.html еще не создался, на этапе его чтения всё падает:
{ [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.


При втором прогоне, когда файл уже скачан, код отрабатывает, но вывод все равно выглядит не так, как должен:
HTML saved to file!
HTML (parsed) saved to file!
25447
40883
15436
Program exited with status code of 0.


Вначале выводится сообщение из нижнего промиса, а только потом - из верхнего.

Почему так получается? Ведь по идее цепочка должна выполняться так: новый .then() вступает в действие только тогда, когда полностью отработал предыдущий. А у меня выходит так, что они работают параллельно, и понятно, что быстрее срабатывает вывод в консоль, а файловые операции медленнее.

Прошу сильно не пинать, асинхронный код в JS мне дается непросто.
  • Вопрос задан
  • 154 просмотра
Решения вопроса 1
megafax
@megafax
web-программист
return fs.outputFile(path, htmlString);
Вы же работаете с асинхронщиной, и каждый следущий промис должен начаться после текущего. Также оберните fs.readFile в return new Promise(), чтобы конечный console.log отрабатывал верно
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы