【问题标题】:Node.js - Run function with callback iterativelyNode.js - 迭代地运行带有回调的函数
【发布时间】:2016-12-07 21:05:41
【问题描述】:

我正在使用 node.js 在 javascript 中开发 API

我想要做的是调用一个函数,该函数触发一系列承诺,并在回调时返回一个包含一个产品信息的数组。

我想要做的是根据需要多次运行此函数,以形成 JSON 格式的产品列表。

但是这个产品列表需要在发回给用户之前创建,这是我苦苦挣扎的地方。

这是我的功能:

exports.findProduct = (ingredient, store, callback) => {
            products.getProductData(ingredient, store)
        .then( data => products.getProducts(data))
        .then( productList => products.filterProductData(productList))
        .then( selectedProduct => callback(null,selectedProduct))//get individual products and add to list
        .catch( err => callback(err))
}

我这样称呼它

products.findProduct(ingredient, 'Waitrose', (err, data) => {

    if (err) {
        //res.send(status.badRequest, {error: err.message})
    } else {
        res.send(data)
        res.end()
    }

})

res.send(data) 将回调中的数据发送回服务器,但如果我想再次运行此函数并更新数组,然后才将数组发送到服务器,该怎么办?

非常感谢任何提示帮助。

【问题讨论】:

    标签: javascript node.js asynchronous callback


    【解决方案1】:

    一种基于 promise 的可能实现,允许 getAllProducts 递归调用自身。

    exports.findProduct = (ingredient, store) => {
        return new Promise((resolve, reject) => {
             products.getProductData(ingredient, store)
            .then( data => products.getProducts(data))
            .then( productList => products.filterProductData(productList))
            .then( selectedProduct => resolve(selectedProduct))
            .catch( err => reject(err))
        }
    }
    
    
    
    function getAllProducts(ingredientList, shopName) {  
        const allProducts = [];
        return new Promise((resolve, reject) => {
            products.findProducts(ingredientList, shopName)
            .then(product => {
                allProducts.push(...product);
    
                if(/*need more products*/) {
                    getAllProducts(ingredientList, 'Tesco')
                    .then(newProducts => {
                        allProducts.push(...newProducts);
                        resolve(allProducts);
                    })
                    .catch(err => reject(err));
                } else {
                    resolve(allProducts);
                }
            })
            .catch(err => reject(err));
        }
    }
    

    这样称呼...

    getAllProducts(ingredientList, 'Waitrose')
    .then(products => {
        res.send(products);
        res.end();
    }).catch(err => {
        res.send(status.badRequest, {error: err.message});
        res.end();
    });
    

    编辑:

    如果需要根据上一次调用的结果来判断是否进行更多调用,上述方法是有效的。如果您事先知道需要拨打多个电话,例如如果您知道要查看 Tesco、Waitrose 和 Asda,那么使用 Promise.all 有一种更简单的方法

    exports.findProduct = (ingredient, store) => {
        return new Promise((resolve, reject) => {
             products.getProductData(ingredient, store)
            .then( data => products.getProducts(data))
            .then( productList => products.filterProductData(productList))
            .then( selectedProduct => resolve(selectedProduct))
            .catch( err => reject(err))
        }
    }
    
    function makeMultipleCalls() {  
        const stores = ['Waitrose', 'Tesco', 'Asda'];
        const promises = [];
    
        for (var store in stores) {
            promises.push(product.findProduct(ingredientList, store);
        }
    
        Promise.all(promises)
        .then(results => {
            res.send(results.reduce((a,b) => a.concat(b)));
            res.end();
        })
        .catch(err => {
            //deal with error
        });
    }
    

    【讨论】:

    • 非常感谢您的回答,只有一个小问题。在 if 语句中,allProducts.push(newProducts) 推入与第一个 allProducts.push(newProducts) 相同的元素。这会导致类似[product1, [product2, [product3]]]] 任何想法如何避免这种情况?干杯
    • 我已经编辑了我的答案以使用扩展 (...) 运算符,因此来自 newProducts 的项目被添加到 allProducts,而不是数组本身。
    • 经过反思,我还想知道是否有更简单的方法可以做到这一点,所以添加了一种不同的方法,可能适合也可能不适合您的情况。
    • for 循环和 promise.all 解决方案非常出色且非常简洁!我设法为产品功能和商店实现了相同的想法。谢谢你,非常感谢你的帮助:)
    猜你喜欢
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 2010-11-21
    • 2011-10-20
    • 1970-01-01
    相关资源
    最近更新 更多