fs.writeFile在一个许诺中,异步同步的东西


77

我的代码需要帮助。我是Node.js的新手,对此有很多麻烦。

我正在尝试做的是:

1)使用亚马逊产品(ASIN)获取.txt;

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

Answers:


175

截至2019年...

...正确的答案是将async / await与node中包含的本机fsPromise模块一起使用。升级到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');
})();

9
请注意,从10.9.0开始,此标记为实验性
rynop

对于Node 8.x,请使用mz / fs库以将fs与async await一起使用。
Spock

1
为避免出现该消息:ExperimentalWarning: The fs.promises API is experimental,请使用node --no-warnings app.js
robe007 '18

1
存在节点没有警告11.x的+
帕斯卡尔Belloncle

1
只要您不使用旧版本的Node,这应该是正确的答案。async并且await是处理异步内容的(美好的)未来。
克利夫顿·拉布鲁姆


55

因为fs.writefile是传统的异步回调-您需要遵循promise规范并返回一个新的promise,将它包装成一个解析和拒绝处理程序,如下所示:

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

3
从Node v8开始,您可以使用util.promisify()将fs I / O函数转换为Promise,例如const util = require('util'); const writeFile = util.promisify(fs.writeFile); ... return writeFile(ASIN + '.json', JSON.stringify(results));
Steve Hansen Smythe

1
从Node v10开始,您可以await fs.直接使用,在下面查看我的答案

15

最后,最新的node.js版本v10.3.0具有本机支持的fs promises。

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


2
const fs = require('fs').promises,而不是/ promises
伦纳德·保利

@LeonardPauli更新了我的答案。
刘易斯

我得到一个类型错误Cannot read property 'writeFile' of undefined。可能是因为此方法没有用于处理二进制字符串的构造函数?:fsPromises.writeFile(tempFile, response.auioContent, 'binary').then(() => { console.log('Audio content written to file: ' + tempFile); return { filePath: "filePath" } })
Adam Hurwitz

看来fs.writeFile(...)现在返回了一个承诺……有人可以确认吗?在then(...)正在达到我的代码部分。
亚当·赫维兹

7

如果要将基于promise的版本导入fs为ES模块,则可以执行以下操作:

import { promises as fs } from 'fs'

await fs.writeFile(...)

释放节点v14后(请参阅此PR),您也可以使用

import { writeFile } from 'fs/promises'

4

2017年9月更新fs-promise已不推荐使用fs-extra


我没有用过,但是您可以研究fs-promise。这是一个节点模块:

代理将所有异步fs方法公开为Promises / A +兼容的Promise(何时,Q等)。将所有同步方法作为值传递。


2
const util = require('util')
const fs = require('fs');

const fs_writeFile = util.promisify(fs.writeFile)

fs_writeFile('message.txt', 'Hello Node.js')
    .catch((error) => {
        console.log(error)
    });

2

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

示例二。使用异步等待:

const fs = require("fs")

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

  console.log("done")
}

writeToFile()

-1

如下所示,在try / catch块中使用fs.writeFileSync。

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

2
永远不要这样做!writeFileSync是一个同步功能,它会停止脚本的执行,并使应用程序变慢,并且无法达到在服务器端使用JS的全部目的。我即时投票,对不起。
Dheeraj

-2

为了易于使用,异步转换所有回调以保证使用诸如“ 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);
    });
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.