【问题标题】:fs.writeFile in a promise, asynchronous-synchronous stuff承诺中的 fs.writeFile,异步同步的东西
【发布时间】:2015-11-05 20:06:18
【问题描述】:

我的代码需要一些帮助。我是 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);
        });
};

【问题讨论】:

    标签: node.js asynchronous synchronization amazon amazon-product-api


    【解决方案1】:

    对我有用的是 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()
    

    【讨论】:

      【解决方案2】:

      如果您想将基于 Promise 的 fs 版本导入为 ES 模块,您可以这样做:

      import { promises as fs } from 'fs'
      
      await fs.writeFile(...)
      

      node v14一发布(见PR),你也可以使用

      import { writeFile } from 'fs/promises'
      

      【讨论】:

        【解决方案3】:

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

        【讨论】:

        • 从 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));
        • 从 Node v10 开始你可以直接使用await fs.,在下面查看我的答案
        【解决方案4】:

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

        【讨论】:

        • 永远不要这样做! writeFileSync 是一个同步函数,它会停止脚本的执行并使应用程序变慢并破坏在服务器端使用 JS 的全部目的。我投反对票,对不起。
        【解决方案5】:

        截至 2019 年...

        ...正确的答案是使用带有 the native fs promises module 包含在节点中的 async/await。升级到 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');
        })();
        

        【讨论】:

        • 请注意,自 10.9.0 起,这已标记为实验性
        • 为了避免消息:ExperimentalWarning: The fs.promises API is experimental,只需使用node --no-warnings app.js
        • 节点11.x+没有警告
        • 这应该是正确的答案,只要您没有卡在旧版本的 Node.js 上。 asyncawait 是处理异步内容的(美丽)未来。
        • 如果你使用import你也可以使用import fs from 'fs/promises';
        【解决方案6】:

        最后,最新的 node.js 版本 v10.3.0 已经原生支持 fs Promise。

        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

        【讨论】:

        • const fs = require('fs').promises,不是 /promises
        • @LeonardPauli 更新了我的答案。
        • 我收到 TypeErrorCannot read property 'writeFile' of undefined。可能是因为这个方法没有处理二进制字符串的构造函数?:fsPromises.writeFile(tempFile, response.auioContent, 'binary').then(() =&gt; { console.log('Audio content written to file: ' + tempFile); return { filePath: "filePath" } })
        • 看来fs.writeFile(...) 现在返回了一个承诺... 有人可以确认一下吗?正在访问我的代码的 then(...) 部分。
        【解决方案7】:
        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)
            });
        

        【讨论】:

          【解决方案8】:

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

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

          这比投票率最高的答案更不容易出错

          【讨论】:

          • util.promisify 已添加到 node.js 版本 8 中。认为此信息可能对考虑使用它的人有所帮助。
          【解决方案9】:

          更新 2017 年 9 月fs-promise 已被弃用,取而代之的是 fs-extra


          我没用过,但你可以看看fs-promise。这是一个节点模块:

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

          【讨论】:

            【解决方案10】:

            为了便于使用异步将所有回调转换为 Promise,请使用“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);
                        });
            

            用 promise 尝试解决方案(蓝鸟)

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

            【讨论】:

              猜你喜欢
              • 2017-12-18
              • 1970-01-01
              • 2021-07-16
              • 1970-01-01
              • 1970-01-01
              • 2022-11-03
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多