Pull to refresh
1
0
Send message

Могу дополнить список: "Mars Will Divide Us" автора Paul Anthony Smith.

Во-первых вказано “Создавайте такие хост-функции, которые принимают коллбэки либо всегда синхронно, либо всегда асинхронно” а про dezalgo не сказано. http://blog.izs.me/post/59142742143/designing-apis-for-asynchrony
Ну а во-вторых, автор допустил ошибку в своей “универсальной” функции


readFileAsArray = function(file, cb = () => {})

Сразу бросилось в глаза значение cb по-умолчанию. И не зря. Потому что в случае когда
1) readFileAsArray принимает колбэк и не использует возвращаемый промис и
2) fs.readFile возвращает ошибку
то срабатывает reject(err), не ловится и вызывает unhandledRejection, что в дальнейшем в статье и происходит


UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: ENOENT: no such file or directory, open

а автор похоже не понимает почему. Уверен, что значение по-умолчанию надо от cb убрать, а тело должно проверять ее наличие


    fs.readFile(file, function(err, data) {
      if (err) {
        if (!cb) return reject(err);
        return cb(err);
      }
      const lines = data.toString().trim().split('\n');
      if (!cb) return resolve(lines);
      cb(null, lines);
    });

Работает, но не параллельно, а последовательно. И я боюсь, что, как и у автора, unhandled rejection. Полностью как у автора, только в массиве.

Короткая запись тоже невозможна. По стандарту await возвращает значение если оно не является промисом. await [ 15, 17 ] должен вернуть массив [ 15, 17 ], не заглядывая внутрь него. Заглядывать внутрь массива — значит тратить время на то, что программисту не нужно. Если программисту нужно явно ждать все промисы массива, на это есть Promise.all.

const arr = await Promise.all([ await1, await2 ]);

именно это и делает. Promise.all создает общий промис, а await ждет его.

Тогда поясню свою позицию про try-catch.
Так как нас даже warning предупреждает (In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code) что unhandled rejection это фатально, то для эмуляции будущих версий (и для fail fast, без unpredicted state) я выполняю per-process что-то типа

process.on('unhandledRejection', (error) => {
console.error('>>> unhandledRejection pid', process.pid);
console.error(error);
process.exit(6);
});

Поэтому у автора два bad practice. Первый — пропускать unhandled rejection, а второй — использовать два await вместо Promise.all. Конечно, если пропускать unhandled rejection, то можно catch если есть await, но чаще всего await просто забыт.
У вас разве в логе нет после единицы UnhandledPromiseRejectionWarning?
Пожалуйста, добейтесь параллельной работы обоих промисов.
Я говорю о таком коде:

const await1 = new Promise((res) => setTimeout(res, 1000));
const await2 = new Promise((_, rej) => setTimeout(rej, 500));
await await1;
await await2;
await await1;
await await2;

К сожалению, этот код будет работать не на 100% корректно. Представьте, что await1 резолвнется (resolve) через 1000мс, а await2 реджектнется (reject) через 500мс. Пока мы ждем await await1, мы НЕ ждем await await2. Таким образом, await2 отработает как unhandled rejection. И мы не сможем поймать ошибку (которая reject(error) внутри await2) в try-catch выше по стеку.

Promise.all([promise1, promise2]) единственный способ когда нужно ждать несколько промисов одновременно. Так как Promise.all начинает ждать (await) все промисы сразу, то и ошибку можно поймать от любого ожидаемого промиса.

Information

Rating
Does not participate
Registered
Activity