【问题标题】:Not sure how to handle this in react - multiple promises不知道如何在反应中处理这个 - 多个承诺
【发布时间】:2018-04-30 08:25:58
【问题描述】:

因此,解释这一点的最简单方法是,我正在尝试在您的 package.json 中搜索您的所有包,然后使用 npm 注册表查看是否有新的更新。我已经完成了大部分工作。接受以下 for 循环:

import request from 'request'

export const findAllUpdates = (packageInfo) => {
  for(prop in packageInfo) {
    request('https://registry.npmjs.org/' + prop, function(err, resp) {
      json = JSON.parse(resp.body);

      if (json['dist-tags'].latest !== packageInfo[prop].version) {
        // Do something, we are not the same version so we should 
        // update some counter.
      }
    });
  }
}

您的 packageInfokey=>value 的对象,它代表 package.json 和 package-lock.json 或 yarn.lock 的依赖项或开发依赖项

重要的部分是我们在上面的函数中查看您安装的内容,然后我们使用注册表获取该软件包信息并将注册表中的最新版本与您安装的版本进行比较,然后我们想要,理想情况下,用总计数更新组件的状态。

问题是我们进入了回调地狱,尤其是使用 for 循环,循环每个包,发出请求。

我无法创建变量并将响应存储在其中,因为在发出请求后无法访问它。我看不出在这里使用事件是如何工作的,因为您可能安装了 40 个软件包作为 dep 或 dev 并且要触发很多事件。

最后,正确的解决方案可能是使用 Promise,但 Promise 的整个概念是更多的回调,带有 .then(() => {}).catch(() => {}),这让我回到了原点。

目标是在一个组件中调用它,并使用必须更新的包的总数(或至少有新版本)更新该组件的状态

有什么想法吗?我是不是搞错了?

【问题讨论】:

    标签: javascript json reactjs callback promise


    【解决方案1】:

    你看promise是对的。

    第一件事是给自己一个启用承诺的request 版本。 util 中有一个 promisify 函数,它采用 Node-callback-style 函数并返回启用承诺的版本。所以:

    import util from 'util';
    // ...
    const prequest = util.promisify(request);
    

    (还有一个 npm 模块,promisify,可以一次完成所有 API。)

    然后,执行您的请求,将 Promise 收集到一个数组中(并在它们上使用 then 进行任何后处理;then 返回一个新的 Promise,所以我们仍然很好),并使用 @987654330 @ 等到他们全部解决(或其中任何一个拒绝);

    所以大家一起来:

    import request from 'request';
    import util from 'util';
    
    const prequest = util.promisify(request);
    
    export const findAllUpdates = (packageInfo) => {
      const updates = []
      for (const prop in packageInfo) {
        updates.push(prequest('https://registry.npmjs.org/' + prop).then(resp => {
          const json = JSON.parse(resp.body);
    
          if (json['dist-tags'].latest !== packageInfo[prop].version) {
            // Do something, we are not the same version so we should 
            // update some counter.
          }
    
          // Perhaps return something here, it will be the resolution
          // for the promise for this request; otherwise, the promise
          // will resolve with `undefined`.
        }));
      }
      return Promise.all(updates);
    };
    

    整个函数的 Promise 将解析为数组中每个 Promise 的结果数组(按顺序),或者如果其中任何一个被拒绝,则(再次)拒绝。

    我希望能够建议async/await,但它目前并没有为一堆并行承诺带来太多好处。 (偶尔有人谈到 await.allPromise.all 所做的事情,但它还没有流行 [还没有?]。)

    话虽如此,但如果我们把事情分开一点,async/await 会更好一些:

    import request from 'request';
    import util from 'util';
    
    const prequest = util.promisify(request);
    
    const checkOne = async (prop) => {
      const resp = await prequest('https://registry.npmjs.org/' + prop);
      const json = JSON.parse(resp.body);
      if (json['dist-tags'].latest !== packageInfo[prop].version) {
        // Do something, we are not the same version so we should 
        // update some counter.
      }
    
      // Perhaps return something here, it will be the resolution
      // for the promise for this request; otherwise, the promise
      // will resolve with `undefined`.
    };
    
    export const findAllUpdates = (packageInfo) => {
      const updates = []
      for (const prop in packageInfo) {
        updates.push(checkOne(prop);
      }
      return Promise.all(updates);
    };
    

    当然,如果packageInfo 中的所有属性都是“自己的”属性(不是继承的),findAllUpdates 会变得简单得多:

    export const findAllUpdates = (packageInfo) => {
      return Promise.all(Object.keys(packageInfo).map(checkOne));
    };
    

    旁注:我在上面添加了一些缺失的声明。

    【讨论】:

      【解决方案2】:

      我建议使用 Promise。您可以进行多个异步调用,然后使用 Promise.all 等待它们。

      如果您还从“findAllUpdates”方法返回一个 Promise,那么调用者很容易在信息可用时更新自己的状态。

      在 React 中是这样的:

      findAllUpdates(..)
        .then(result => this.setState({
          packagesNeedUpdate: result.filter(p => !p.latest).length
        }));
      

      我在下面创建了一个使用 Promise 的简单示例。它会伪造请求,但除此之外应该非常准确。

      // Fake requests. Will return version '1.0.0' after one second.
      const makeRequest = url => {
        return new Promise(resolve => {
          setTimeout(() => {
            resolve(JSON.stringify({
              'dist-tags': {
                'latest': '1.0.0'
              }
            }, null, 2));
          }, 1000);
        });
      }
      
      const findAllUpdates = (packageInfo) => {
        return new Promise(resolve => {
          const promises = Object.keys(packageInfo)
            .map(prop => makeRequest('https://registry.npmjs.org/' + prop).then(JSON.parse));
            
          Promise.all(promises) // Wait for all promises
            .then(jsons => {
              const results = Object.keys(packageInfo)
                .map((prop, i) => {
                  const latestInNpm = jsons[i]['dist-tags'].latest;
                  const current = packageInfo[prop].version
                  return {
                    prop,
                    latest: latestInNpm === current
                  }
                });
              resolve(results); // Return result to caller
            });
        });
      }
      
      function run() {
        console.log('Loading..');
        
        const packages = {
          'react': {version: '0.0.1'},
          'angular': {version: '1.0.0'},
          'ember': {version: '0.5.0'},
          'mithril': {version: '0.9.0'}
        };
        
        findAllUpdates(packages).then(result => {
          const needUpdates = result.filter(p => !p.latest).length;
          console.log('Need updates: ', needUpdates);
        });
      }
      
      run();

      【讨论】:

        猜你喜欢
        • 2013-11-16
        • 2018-11-07
        • 2020-05-09
        • 2019-05-08
        • 2016-06-19
        • 1970-01-01
        • 2014-11-22
        • 2021-04-10
        相关资源
        最近更新 更多