2016-10-03 44 views
-1

大量的研究和測試後,我stucked到我的瀑布:fs.readFile內async.waterfall不返回數據

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

您可以在之前顯示函數的回調嗎?你確定你傳遞了一個有效的'imgName'嗎? – DrakaSAN

+0

我想你必須在這裏展示更多的執行上下文,包括如何設置'imgName',以及這個函數與其他函數可能有什麼不同。這裏沒有足夠的信息顯示。 – jfriend00

+0

嗨,謝謝你的答案,是的非常確定imgName是好的,也嘗試使用文件名「硬編碼」,而不是var名稱。也嘗試了一個錯誤的文件名,然後該函數按預期拋出錯誤。 – direxit

回答

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

僅供參考,它的概念奇怪,在一個步驟中的數據寫入到文件和然後在下一步中將其讀回到內存中。相當低效。爲什麼不把它第一次讀入內存,或者如果你仍然希望它在一個文件中,然後將它寫入一個文件,但在內存中保留你寫的數據?

+0

@direxit:您可以點擊旁邊的綠色標記將答案標記爲正確。你也收到代表。 – DrakaSAN

+0

添加修補程序的代碼示例。 – jfriend00

+0

@ jfriend00你是老闆! *****,是那個流未完成的東西,是的,我可以避免一步:) – direxit