async.waterfall中的fs.readFile不会返回数据

时间:2016-10-03 14:39:40

标签: node.js asynchronous

经过大量的研究和测试,我被困在了瀑布中:

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

1 个答案:

答案 0 :(得分: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);
    });

仅供参考,在一步中将数据写入文件然后在下一步中将其读回内存中,概念上很奇怪。效率很低。为什么不在第一次进入内存时读取它,或者如果你仍然想要它在文件中,然后将其写入文件,但在内存中保留你写的数据?