Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/36.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何优化这段代码,因为它是异步的_Javascript_Node.js_Asynchronous_Conditional - Fatal编程技术网

Javascript 如何优化这段代码,因为它是异步的

Javascript 如何优化这段代码,因为它是异步的,javascript,node.js,asynchronous,conditional,Javascript,Node.js,Asynchronous,Conditional,如您所见,对_data.read的调用是异步的,因为我是从文件中读取的 但是我需要等待读取所有文件,这样我才能计算出总价。这就是为什么我放置该条件[++I==userData.shoppingcart.length] 一般来说,我对javascript和nodejs都是新手,从来都不是一个很好的程序员,但无论如何,我的观点是,我确信这不是一个好的方法,如果两个文件同时读取,然后该条件从未运行过,或者totalPrice的计算做得很糟糕,会怎么样 有人能给我一些指导吗? 提前谢谢你 这就是如何使用

如您所见,对_data.read的调用是异步的,因为我是从文件中读取的

但是我需要等待读取所有文件,这样我才能计算出总价。这就是为什么我放置该条件[++I==userData.shoppingcart.length]

一般来说,我对javascript和nodejs都是新手,从来都不是一个很好的程序员,但无论如何,我的观点是,我确信这不是一个好的方法,如果两个文件同时读取,然后该条件从未运行过,或者totalPrice的计算做得很糟糕,会怎么样

有人能给我一些指导吗?
提前谢谢你

这就是如何使用promises(Flavor)按顺序阅读项目:


本例假设
\u data.read
支持
异步/await
。但是,如果没有,它可以使用nodejs模块中的
promisify
函数“promisified”

鉴于您没有指定这是在什么上下文中,我将做一些假设:

  • 我假设
    \u data.read()
    不支持返回承诺
  • 我假设这段代码需要调用回调函数或返回承诺
  • 我(有些天真)的做法是:

  • orderItems
    映射为该商品每个价格的承诺
  • 将结果映射为一个总数
  • 返回结果承诺或调用回调
  • 下面是一个带注释的示例,说明了您可以如何执行此操作:

    var orderItems = userData.shoppingcart;
    
    let totalPrice = 0;
    for (let itemName of userData.shoppingcart) {
      const itemData = await _data.read('menuitems', itemName);
      totalPrice += itemData.price;
    }
    
    如果你能回报一个承诺,而你只想回报总数,那么

    // Promise.all takes an array of promises and returns
    // a new promise that completes when all the promises in the array are complete.
    const promiseOfPrices = Promise.all(
        // Here we map all the items in the shopping cart into promises for each of their prices
        userData.shoppingcart.map(
    
            // The Promise object takes a single function that it will immediatly call with functions to resolve or
            // reject the promise. I suggest reading up on Promises if you're not familiar with them.
            itemName => new Promise((resolve, reject) => {
                // Here, we have a `reject` and `resolve` function that will each complete the new promise,
                // either in success or error respectfully.
    
                // Do the actual read of your file or database or whatever
                _data.read('menuitems', itemName, (err, itemData) => {
                    // If there was an error, reject this promise.
                    if (err) reject(err);
    
                    // Otherwise, we're successful and we resolve with the price of the item
                    else resolve(itemData.price);
                });
            })
        )
    );
    
    // Now, we have a promise (promiseOfPrices) for all the prices of the items in the cart. We use `then` which will
    // perform a transform on the result, much like the `map` function on an Array.
    
    const promiseOfTotal = promiseOfPrices.then(
        // Here we use the `Array.reduce` function to succinctly sum the values in the array.
        arrayOfCartItemPrices => arrayOfCartItemPrices.reduce(
            // For each item, reduce calls our function with the current sum and an item in the array. We produce a new
            // sum by adding the sum to the item price.
            (sum, itemPrice) => sum + itemPrice,
    
            // This is the initial value for sum, 0.
            0
        )
    );
    
    如果您有一个预期(err,result)的回调,则执行以下操作:

    return promiseOfTotal;
    
    如果您需要对结果做更多的工作,您可以使用另一个来完成,然后:

    promiseOfTotal.then(
        result => callback(null, result),
        error => callback(error, null),
    )
    
    注意,通过使用承诺、箭头函数和数组理解(
    map
    reduce
    ),我们避免了变量和循环的复杂和难以跟踪的变异。这是一种“函数式”编程风格,虽然学习起来有些困难,但通常比其他编程方式更安全、更干净。我建议您花点时间来理解它是如何工作的,因为它可以帮助您编写代码,在处理异步等复杂问题时,代码不太可能出现错误

    最后,我还没有运行这段代码。它很可能有一两个bug。如果不起作用,请随时要求澄清

    祝你好运


    另外,我没有使用
    async
    /
    await
    ,因为我认为这比直接使用承诺和使用
    Promise要不清楚。无论如何,并行性都需要所有的
    。在这里完全可以使用它们来获得良好的效果,但我将把它作为练习留给OP.

    “如果同时读取两个文件会怎么样”-这不正是您想要的吗?基本上,是的,这就是想法-计算完成了多少任务,然后继续。不过也有很多陷阱,比如正确地考虑错误或者0次迭代的边缘情况(比如在空输入上),因此您最好使用一些经过验证的现有代码,而不是重新发明轮子。了解承诺和
    Promise.all
    。是的,它们都可以同时读取,但我希望流量只有在所有内容都已读取后才能继续,因此我有正确和准确的totalPrice变量量。是的,我听说过Promise,但不知道如何使用它,我会对此进行一些搜索,谢谢@BergiYeah,这是按顺序运行的,而不是并行运行的,这可能是不可取的。我对
    async
    /
    await
    最大的一个问题是,它似乎鼓励减少并行代码。@bergi是的,在这种情况下,
    async/await
    会将其添加到答案中。@YonaAppletree我发现,优化可读性而不是性能是可取的。@Christian当然。但是有表现,有表现。在本例中,您将获取可能是O(1)的内容并将其转换为O(N)。这与使用理解时创建的中间数组不同。O(1)对O(N)是巨大的,特别是当存在网络或文件读取或其他情况时。这至少值得仔细考虑。嗨@YonaAppletree非常感谢你的详细回答,从未使用过承诺,现在是学习它们的好时机!我相信我理解了你的逻辑,大体上理解了你的代码。我刚问了一个问题,承诺价格将是所有价格的数组,对吗?在这种情况下,如果有一个拒绝,我会知道,因为数组“promiseOfPrices”的长度将不同于我预期的长度,对吗?为了澄清,我现在接受你的详细回答:)@TiagoM承诺是一个非常好的抽象概念,我建议你阅读这些文件,因为我在一篇文章中所能说的不止这些。回答您的问题:否。
    Promise.all
    生成一个新的承诺,当传递给它的所有承诺都解决(成功)或拒绝其中任何一个时,它将解决(失败)。因此,
    promiseOfPrices
    将是一个承诺,通过一系列的价格来解决。它永远不会使用不同长度的数组进行解析。如果任何一个都失败了,
    promiseOfPrices
    promiseOfPrices将以第一个错误拒绝(失败)。谷歌关于承诺的介绍性教程看起来相当不错:换句话说,如果你想知道是否出了问题,看看我给出的关于做更多工作的示例,其中有两个参数是
    。然后()
    或者您可以使用
    .catch()
    捕捉错误。您好@YonaAppletree只是想路过这里,感谢您提供的文档和解释!我终于让它按照我需要的方式工作了,使用了promissions.All-and-Then子句,我还将阅读您发送给我的文档,因为它听起来非常有文档记录!再次感谢您的帮助和宝贵时间!祝你一切顺利;)
    promiseOfTotal.then(
        result => callback(null, result),
        error => callback(error, null),
    )
    
    promiseOfTotal.then(
        priceSum => {
            // Do work here
        },
        // Optionally handle errors here:
        error => {
            // Do error handling here.
        }
    )