fs.writeFile в обещании, асинхронно-синхронный материал

Мне нужна помощь с моим кодом. Я новичок в Node.js и у меня много проблем с этим.

Что я пытаюсь сделать:

1) Получите .txt с продуктами Amazon (ASIN);

2) Получите все продукты с помощью пакета amazon-product-api;

3) Сохраните каждый продукт в файле .json.

Мой код не работает. Я думаю, что напортачил с асинхронно-синхронной штукой - помоги мне!

var amazon = require('amazon-product-api');
var fs = require('fs');

var client = amazon.createClient({
    awsId: "XXX",
    awsSecret: "XXX",
    awsTag: "888"
});

var array = fs.readFileSync('./test.txt').toString().split('\n');
for (var i = 1; i < array.length; i++) {
     var ASIN = array[i];

    return client.itemLookup({
            domain: 'webservices.amazon.de',
            responseGroup: 'Large',
            idType: 'ASIN',
            itemId: ASIN
        })
        .then(function(results) {
            fs.writeFile(ASIN + '.json', JSON.stringify(results), function(err) {
                if (err) {
                    console.log(err);
                } else {
                    console.log("JSON saved");
                }
            })

            return results;

        }).catch(function(err) {
            console.log(err);
        });
};

person Markus Schmidlich    schedule 13.08.2015    source источник


Ответы (9)


As of 2019...

... правильный ответ - использовать async / await с встроенный fs модуль promises, включенный в узел. Обновитесь до Node.js 10 или 11 (уже поддерживаемого основными поставщиками облачных услуг) и сделайте следующее:

const fs = require('fs').promises;

// This must run inside a function marked `async`:
const file = await fs.readFile('filename.txt', 'utf8');
await fs.writeFile('filename.txt', 'test');

Не используйте сторонние пакеты и не пишите свои собственные оболочки, в этом больше нет необходимости.

Больше не экспериментальный

До появления Node 11.14.0 вы все равно получали бы предупреждение о том, что эта функция является экспериментальной, но она работает нормально, и это решение будет продолжаться в будущем. Начиная с 11.14.0, эта функция больше не является экспериментальной и готова к производству.

Что, если я предпочитаю import вместо require?

Это тоже работает, но только в версиях Node.js, где эта функция не помечена как экспериментальная.

import { promises as fs } from 'fs';

(async () => {
    await fs.writeFile('./test.txt', 'test', 'utf8');
})();
person Community    schedule 30.08.2018
comment
Внимание! В версии 10.9.0 это отмечено как экспериментальное. - person rynop; 06.09.2018
comment
Для Node 8.x используйте библиотеку mz / fs для использования fs с async await. - person Spock; 13.10.2018
comment
Чтобы избежать сообщения: ExperimentalWarning: The fs.promises API is experimental, просто используйте node --no-warnings app.js - person robe007; 05.11.2018
comment
в узле 11.x нет предупреждения - person Pascal Belloncle; 09.05.2019
comment
Это должен быть правильный ответ, если вы не застряли на старой версии Node. async и await - это (прекрасное) будущее обработки асинхронного материала. - person Clifton Labrum; 31.05.2019
comment
Совершенно уверен, что здесь в асинхронной версии есть ошибка. Должно быть `` const file = await fs.readFile ('filename.txt', 'utf8'); ожидание fs.writeFile ('filename.txt', 'test'); `` '' - person EdL; 11.05.2020
comment
Если вы используете import, вы также можете использовать import fs from 'fs/promises'; - person Patrick Wozniak; 19.12.2020

сказать

const util = require('util')
const fs_writeFile = util.promisify(fs.writeFile)

https://nodejs.org/api/util.html#util_util_promisify_original

это менее подвержено ошибкам, чем ответ, получивший наибольшее количество голосов

person amara    schedule 18.11.2017
comment
util.promisify был добавлен в node.js версии 8. Подумал, что эта информация может быть полезна людям, которые собираются ее использовать. - person Tim; 28.11.2017

Поскольку fs.writefile является традиционным асинхронным обратным вызовом, вам необходимо следовать спецификации обещания и вернуть новое обещание, обернув его обработчиком разрешения и отклонения, например:

return new Promise(function(resolve, reject) {
    fs.writeFile("<filename.type>", data, '<file-encoding>', function(err) {
        if (err) reject(err);
        else resolve(data);
    });
});

Итак, в своем коде вы бы использовали его так сразу после вызова .then():

 .then(function(results) {
    return new Promise(function(resolve, reject) {
            fs.writeFile(ASIN + '.json', JSON.stringify(results), function(err) {
               if (err) reject(err);
               else resolve(data);
            });
    });
  }).then(function(results) {
       console.log("results here: " + results)
  }).catch(function(err) {
       console.log("error here: " + err);
  });
person AntonB    schedule 04.02.2016
comment
Начиная с Node v8, вы можете использовать util.promisify () для преобразования функций ввода-вывода fs в обещания, например const util = require('util'); const writeFile = util.promisify(fs.writeFile); ... return writeFile(ASIN + '.json', JSON.stringify(results)); - person Steve Hansen Smythe; 01.08.2018
comment
Начиная с Node v10 вы можете использовать await fs. напрямую, посмотрите мой ответ ниже - person ; 30.08.2018

Наконец, последний выпуск node.js v10.3.0 имеет встроенную поддержку обещаний fs.

const fsPromises = require('fs').promises; // or require('fs/promises') in v10.0.0
fsPromises.writeFile(ASIN + '.json', JSON.stringify(results))
  .then(() => {
    console.log('JSON saved');
  })
  .catch(er => {
    console.log(er);
  });

Вы можете проверить официальную документацию для получения более подробной информации. https://nodejs.org/api/fs.html#fs_fs_promises_api

person Lewis    schedule 13.05.2018
comment
const fs = require('fs').promises, а не / обещает - person Leonard Pauli; 31.05.2018
comment
@LeonardPauli Обновил мой ответ. - person Lewis; 03.06.2018
comment
Я получаю TypeError: Cannot read property 'writeFile' of undefined. Возможно, потому что у этого метода нет конструктора для обработки двоичных строк ?: fsPromises.writeFile(tempFile, response.auioContent, 'binary').then(() => { console.log('Audio content written to file: ' + tempFile); return { filePath: "filePath" } }) - person Adam Hurwitz; 09.12.2018
comment
Похоже, fs.writeFile(...) теперь возвращает обещание ... Кто-нибудь, пожалуйста, подтвердите? Достигнута then(...) часть моего кода. - person Adam Hurwitz; 09.12.2018

Если вы хотите импортировать основанную на обещаниях версию fs в качестве модуля ES, вы можете сделать:

import { promises as fs } from 'fs'

await fs.writeFile(...)

Как только узел v14 будет выпущен (см. Этот PR), вы также можете использовать

import { writeFile } from 'fs/promises'
person Kim Kern    schedule 22.04.2020

Обновление сентябрь 2017 г.: fs-promise устарел и заменен на _ 2_.


Я не использовал его, но вы можете изучить fs-обещание. Это узел узла, который:

Проксирует все методы async fs, выставляя их как обещания, совместимые с Promises / A + (when, Q и т. Д.). Передает все методы синхронизации как значения.

person rouan    schedule 17.11.2015

Что сработало для меня, так это fs.promises.

Пример первый:

const fs = require("fs")

fs.promises
  .writeFile(__dirname + '/test.json', "data", { encoding: 'utf8' })
  .then(() => {
    // Do whatever you want to do.
    console.log('Done');
  });

Пример второй. Использование Async-Await:

const fs = require("fs")

async function writeToFile() {
  await fs.promises.writeFile(__dirname + '/test-22.json', "data", {
    encoding: 'utf8'
  });

  console.log("done")
}

writeToFile()
person Divine Hycenth    schedule 19.10.2020

Используйте fs.writeFileSync внутри блока try / catch, как показано ниже.

`var fs = require('fs');
 try {
     const file = fs.writeFileSync(ASIN + '.json', JSON.stringify(results))
     console.log("JSON saved");
     return results;
 } catch (error) {
   console.log(err);
  }`
person Rahul Sadaphal    schedule 01.08.2019
comment
никогда не делай этого! writeFileSync - это синхронная функция, которая останавливает выполнение скрипта, замедляет работу приложения и сводит на нет всю цель использования JS на стороне сервера. Я голосую против, извините. - person Dheeraj; 26.12.2019

Для упрощения использования асинхронного преобразования всех обратных вызовов в обещание используйте некоторую библиотеку, например "bluebird".

      .then(function(results) {
                fs.writeFile(ASIN + '.json', JSON.stringify(results), function(err) {
                    if (err) {
                        console.log(err);
                    } else {
                        console.log("JSON saved");
                        return results;
                    }
                })


            }).catch(function(err) {
                console.log(err);
            });

Попробуйте решение с обещанием (bluebird)

var amazon = require('amazon-product-api');
var fs = require('fs');
var Promise = require('bluebird');

var client = amazon.createClient({
    awsId: "XXX",
    awsSecret: "XXX",
    awsTag: "888"
});


var array = fs.readFileSync('./test.txt').toString().split('\n');
Promise.map(array, function (ASIN) {
    client.itemLookup({
        domain: 'webservices.amazon.de',
        responseGroup: 'Large',
        idType: 'ASIN',
        itemId: ASIN
    }).then(function(results) {
        fs.writeFile(ASIN + '.json', JSON.stringify(results), function(err) {
            if (err) {
                console.log(err);
            } else {
                console.log("JSON saved");
                return results;
            }
        })
    }).catch(function(err) {
        console.log(err);
    });
});
person trquoccuong    schedule 13.08.2015