" async.forEach" itetarion停止,直到请求获得输出

时间:2017-08-02 05:13:05

标签: node.js asynchronous foreach request async.js

除了这一行之外,这段代码完美无缺:" inventory [asset.assetid] .floatvalue = getFloat"。正如您所看到的那样,它处于异步模式,并且此行初始化了一个获取某些值的请求,但它无法获得它未定义的值。我测试了它,以及请求中的主要问题,这也是异步的。所以答案是如何停止异步模式并等待请求的返回。

    'use strict'

    const config = require('../config');
    const request = require('request');
    const async = require('async');
    const Trade = require('./index');

    const MAX_RETRIES = 3;
    const API_URL = 'https://api.steamapis.com/steam/inventory';
    const floaturl = 'https://api.csgofloat.com:1738/';




    Trade.prototype.getInventory = function getInventory(steamID64, appID, contextID, callback, retries) {


request(`${API_URL}/${steamID64}/${appID}/${contextID}?api_key=${config.SteamApisKey}`, (error, response, body) => {
    if (!error && response.statusCode === 200) {
        const items = JSON.parse(body)
        const assets = items.assets
        const descriptions = items.descriptions

        const inventory = {}



        if ( descriptions && assets ) {

            async.forEach(descriptions, (description, cbDesc) => async.forEach(assets, (asset, cbAsset) => {

                if (description.classid === asset.classid && description.tradable && description.marketable && description.market_hash_name.indexOf('Souvenir') === -1 ) {
                    if (typeof inventory[asset.assetid] !== 'undefined') {
                        return true
                    }
                    const type = Trade.prototype.getItemType(description.market_hash_name, description.type)
                    const wear = Trade.prototype.getItemWear(description.market_hash_name)
                    const inspect = Trade.prototype.getInspect(steamID64, asset.assetid, description.actions)
                    const getFloat = Trade.prototype.getFloat(inspect, asset.assetid, function(_float){

                        var data = String(_float);
                        inventory[asset.assetid].floatvalue = data; // inside the callback, at this moment judging by the consol the data is defined,but outside the callback the data is not appreciated to inventory[asset.assetid].floatvalue 




                    });




                    inventory[asset.assetid] = asset
                    inventory[asset.assetid].item_type = type
                    inventory[asset.assetid].item_wear = wear
                    inventory[asset.assetid].inspect = inspect
                    inventory[asset.assetid].floatvalue = getFloat // this line does not work properly
                    inventory[asset.assetid].data = {
                        background: description.background_color,
                        image: description.icon_url,
                        tradable: description.tradable,
                        marketable: description.marketable,
                        market_hash_name: description.market_hash_name,
                        type: description.type,
                        color: description.name_color,
                    }

                }



                return cbAsset()
            }, cbDesc))

        }


        return callback(null, inventory)
    }














    let retry = retries
    if (typeof retries === 'undefined') {
        retry = 0
    }
    retry += 1
    if (retry <= MAX_RETRIES) {
        return Trade.prototype.getInventory(steamID64, appID, contextID, callback, retries)
    }
    let statusCode = null
    if (typeof response !== 'undefined' && typeof response.statusCode !== 'undefined') {
        statusCode = response.statusCode
    }
    return callback({ error, statusCode })
})
}

Trade.prototype.getInventories = function getInventories(params, callback) {
const inventories = {}
async.each(params, (user, cb) => {
    Trade.prototype.getInventory(user.steamID64, user.appID, user.contextID, (err, data) => {
        inventories[user.id] = {}
        inventories[user.id] = {
            error: err,
            items: (!err) ? Object.keys(data).map(key => data[key]) : null,
        }
        cb()
    })
}, () => {
    callback(inventories)
})
}

Trade.prototype.getItemType = function getItemType(marketHashName, type) {
if (marketHashName.indexOf('Key') !== -1) {
    return { value: 0, name: 'key' }
}
if (marketHashName.indexOf('★') !== -1) {
    return { value: 1, name: 'knife' }
}
if (
    type.indexOf('Classified') !== -1 ||
    type.indexOf('Contraband') !== -1 ||
    type.indexOf('Covert') !== -1
) {
    return { value: 2, name: 'rare_skin' }
}
if (
    type.indexOf('Consumer Grade') !== -1 ||
    type.indexOf('Base Grade') !== -1 ||
    type.indexOf('Graffiti') !== -1 ||
    type.indexOf('Sticker') !== -1 ||
    type.indexOf('Industrial Grade') !== -1
) {
    return { value: 4, name: 'misc' }
}
return { value: 3, name: 'weapon' }
}

Trade.prototype.getItemWear = function getItemWear(marketHashName) {
if (marketHashName.indexOf('Factory New') !== -1) {
    return 'FN'
}
if (marketHashName.indexOf('Minimal Wear') !== -1) {
    return 'MW'
}
if (marketHashName.indexOf('Field-Tested') !== -1) {
    return 'FT'
}
if (marketHashName.indexOf('Well-Worn') !== -1) {
    return 'WW'
}
if (marketHashName.indexOf('Battle-Scarred') !== -1) {
    return 'BS'
}
return false
}

Trade.prototype.getInspect = function getInspect (steamID64, assetid, actions) {
let inspectLink = null;                                           
if (actions) {
    for (const a in actions) {
        if (actions[a].name.indexOf('Inspect') !== -1) {
               inspectLink = actions[a].link
               inspectLink = inspectLink.replace('%owner_steamid%', steamID64)
               inspectLink = inspectLink.replace('%assetid%', assetid)
        }
    }
}
return inspectLink
}

Trade.prototype.getFloat = function getFloat (adding, callback) {

request ("https://api.csgofloat.com:1738/?url=" + adding, (error, response, body) => {

     if (!error && response.statusCode == 200) {

         var floatBody = JSON.parse(body);
         var float = floatBody["iteminfo"]["floatvalue"];
         var id = id;
         if (float != "") {

             callback(float);
         } else {
             return "wrong";
         }
     } else {
        console.log('something goes wrong');
        return "wrong";
    }

});

}

1 个答案:

答案 0 :(得分:0)

只需移动定义inventory[asset.assetid]的回调中的data行块。

if (
    description.classid !== asset.classid ||
    !description.tradable || 
    !description.marketable ||
    description.market_hash_name.indexOf('Souvenir') > -1
) {
    return cbAsset()
}

if (typeof inventory[asset.assetid] !== 'undefined') {
    return cbAsset()
}

const type = Trade.prototype.getItemType(description.market_hash_name, description.type)
const wear = Trade.prototype.getItemWear(description.market_hash_name)
const inspect = Trade.prototype.getInspect(steamID64, asset.assetid, description.actions)
const getFloat = Trade.prototype.getFloat(inspect, asset.assetid, function(_float){
    var data = String(_float);
    inventory[asset.assetid].floatvalue = data;
    inventory[asset.assetid] = asset
    inventory[asset.assetid].item_type = type
    inventory[asset.assetid].item_wear = wear
    inventory[asset.assetid].inspect = inspect
    inventory[asset.assetid].data = {
        background: description.background_color,
        image: description.icon_url,
        tradable: description.tradable,
        marketable: description.marketable,
        market_hash_name: description.market_hash_name,
        type: description.type,
        color: description.name_color,
    };
    return cbAsset();
});

侧面备注:

(1)我总是发现return early更好,以避免代码混乱。

(2)确保在每次操作中始终至少触发回调,即cbDesccbAsset,最多一次。如果您没有正确执行此操作,您的代码将挂起或触发错误。

(3)如果Trade.getItemType()Trade.getItemWear()Trade.getInspect()Trade.getInspect()都是异步的,那么您可能需要使用另一个async函数(例如async.series()async.parallel())并等待其最终回调以执行inventory[asset.assetid]行。