【问题标题】:fs.readFile inside async.waterfall doesn't return dataasync.waterfall 中的 fs.readFile 不返回数据
【发布时间】:2016-10-04 00:22:02
【问题描述】:

经过大量研究和测试,我陷入了我的瀑布:

async.waterfall([
  //first 5 functions are going fine and passing expected vars to the next function the function below is the pb
  // eg adSetId var comes just fine from previous function
  function(imgName,adsetId,callback) {
    fs.readFile('./shopifyImages/'+imgName  , 'base64' ,function(err,imgData) {
      callback(null,imgData,adsetId);
    });
  }
]);

imgData 总是返回空值。 该函数没有错误,它在瀑布外正常工作(fs.readFile 按预期工作),一些console.log 也给出了空的imgData

完整代码

async.waterfall([
    //GET AD ACCOUNT FOR USER
    function(callback) {
        var sqlAd_act = vsprintf('select * from fbTokens where userId=%s', [roomIDCook.userId]);
        connection.query(sqlAd_act).then(function(rows) {
            //console.log('rows '+rows);
            callback(null, rows[0].ad_act);
        });
    },
    //SET CAMPAIGN
    function(ad_act, callback) {
        fb.api('/act_' + ad_act + '/campaigns', 'post', {
            'status': 'PAUSED',
            'name': 'GENIE 2'
        }, function(data) {
            //console.log('data: ' + util.inspect(data))
            callback(null, data.id, ad_act);
        });
    },
    //SET ADSET
    function(campaignId, ad_act, callback) {
        console.log('ad account ' + ad_act);
        console.log('campaignId ' + campaignId);
        fb.api('/act_' + ad_act + '/adsets', 'post', {
            'daily_budget': 500,
            'start_time': '2017-02-18T20:11:25+0000',
            'end_time': '2017-03-25T20:11:25+0000',
            'name': 'new adset',
            'optimization_goal': 'LINK_CLICKS',
            'objective': 'LINK_CLICKS',
            'campaign_id': campaignId,
            'status': 'PAUSED',
            'billing_event': 'LINK_CLICKS',
            'bid_amount': 2,
            'targeting': {
                "geo_locations": {
                    "countries": ["US"]
                },
                "publisher_platforms": ["facebook"]
            }
        },
        function(res) {
            if (!res || res.error) {
                console.log(!res ? 'error occurred' : util.inspect(res.error));
                return;
            }
            //console.log(util.inspect(res));
            callback(null, res.id)
        });
    },
    // CREATE THE AD FOR THE ADSET
    function(adsetId, callback) {
        // set img
        var imgUri = 'https://cdn.shopify.com/s/files/1/1336/5343/products/9_b75df43c-1660-4aeb-89b7-418df1a9853c_1024x1024.jpg?v=1466985077';
        var DOWNLOAD_DIR = 'shopifyImages/';
        var imgName = 'TEST2.jpg';
        console.log('adsetId ' + adsetId);
        // download img
        request.head(imgUri, function(err, res, body) {
            console.log('content-type:', res.headers['content-type']);
            console.log('content-length:', res.headers['content-length']);
            request(imgUri).pipe(fs.createWriteStream(DOWNLOAD_DIR + imgName));
            console.log('adsetId ' + adsetId);
            callback(null, imgName, adsetId);
        });
        // read img for facebook
    },
    function(imgName, adsetId, callback) {
        fs.readFile('./shopifyImages/' + imgName, 'base64', function(err, imgData) {
            console.log(util.inspect(err));
            console.log(util.inspect(imgData));
            callback(null, imgData, adsetId);
        });
    },
    function(imgData, adsetId, callback) {
        console.log(imgData);
        console.log('adsetId ' + adsetId);
    }
], function(error, c) {
    console.log(c);
});

【问题讨论】:

  • 你能显示之前函数的回调吗?你确定你传递的是一个有效的imgName
  • 我认为你必须在这里展示更多的执行上下文,包括如何设置imgName,以及这个函数与其他函数可能有什么不同。此处显示的信息不足。
  • 您好,谢谢您的回答,是的,很确定 imgName 很好,也尝试使用文件名“硬编码”而不是 var 名称。还尝试使用错误的文件名,然后该函数按预期抛出错误。
  • 你也不检查错误,你能console.log它并告诉我们结果吗?
  • 如果它在外部而不是内部工作正常,您可能提供了不正确的参数。

标签: node.js asynchronous


【解决方案1】:

由于流是异步的,因此存在时间问题。你正在这样做:

request(imgUri).pipe(fs.createWriteStream(DOWNLOAD_DIR + imgName));
callback(null, imgName, adsetId);

但是,在调用callback() 并继续下一步之前,您不需要等待流完成,您希望imgName 文件已经存在。因此,您正在尝试在新创建的文件完成写入之前读取它。

您需要为该流注册一个事件处理程序,以便知道该流何时完成写入,然后才应该调用callback(null, imgName, adsetId) 继续下一步。

我不是流高手,所以可能有更优雅的方法可以做到这一点,但这里有一个解决方案:

// CREATE THE AD FOR THE ADSET
function(adsetId, callback) {
    // set img
    var imgUri = 'https://cdn.shopify.com/s/files/1/1336/5343/products/9_b75df43c-1660-4aeb-89b7-418df1a9853c_1024x1024.jpg?v=1466985077';
    var DOWNLOAD_DIR = 'shopifyImages/';
    var imgName = 'TEST2.jpg';
    console.log('adsetId ' + adsetId);
    // download img
    request.head(imgUri, function(err, res, body) {
        console.log('content-type:', res.headers['content-type']);
        console.log('content-length:', res.headers['content-length']);
        console.log('adsetId ' + adsetId);
        var outputStream = fs.createWriteStream(DOWNLOAD_DIR + imgName);
        outputStream.on('finish', function() {
            callback(null, imgName, adsetId);
        });
        outputStream.on('error', function(err) {
            callback(err);
        });
        request(imgUri).pipe(outputStream);
    });

仅供参考,在一个步骤中将数据写入文件然后在下一步将其读回内存在概念上很奇怪。相当低效。为什么不只是第一次将其读入内存,或者如果您仍希望将其保存在文件中,然后将其写入文件,而是将您写入的数据保留在内存中?

【讨论】:

  • @direxit:您可以通过单击旁边的绿色标记将答案标记为正确。你也会因此获得代表。
  • @jfriend00 你是老板! *****,那是流未完成的事情吗,是的,我可以避免一步:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多