为什么我的解决方案如此缓慢?如何提高查询的性能?

时间:2017-06-20 13:43:05

标签: javascript node.js firebase google-cloud-platform google-cloud-storage

目前我能够优化性能,但仍然有点慢:/

最新编辑:

我目前的解决方案(最快的atm(但仍然很慢)并保持秩序):

服务器

router.post('/images', function(req, res, next) {
    var image = bucket.file(req.body.image);
    image.download(function(err, contents) {
        if (err) {
            console.log(err);
        } else {
            var resultImage = base64_encode(contents);
            var index = req.body.index;
            var returnObject = {
                image: resultImage,
                index: index
            }
            res.send(returnObject);
        }
    });
});

客户查询

$scope.getDataset = function() {

                fb.orderByChild('id').startAt(_start).limitToFirst(_n).once("value", function(dataSnapshot) {

                    dataSnapshot.forEach(function(childDataSnapshot) {
                        _start = childDataSnapshot.child("id").val() + 1;

                        var post = childDataSnapshot.val();
                        var image = post.image;

                        var imageObject = {
                            image: image,
                            index: position
                        };
                        position++;
                        $.ajax({
                            type: "POST",
                            url: "images",
                            data: imageObject,
                        }).done(function(result) {
                            post.image = result.image;
                            $scope.data[result.index] = post;
                            $scope.$apply();
                            firstElementsLoaded = true; 
                        });
                    })  
                });
            };

客户端HTML

<div ng-controller="ctrl">
        <div class="allcontent">
            <div id="pageContent" ng-repeat="d in data track by $index"><a href="details/{{d.key}}" target="_blank"><h3 class="text-left">{{d.title}}<a href="../users/{{d.author}}"><span class="authorLegend"><i> by {{d.username}}</i></span></a></h3>
                </a>
                <div class="postImgIndex" ng-show="{{d.upvotes - d.downvotes > -50}}">
                    <a href="details/{{d.key}}" target="_blank"><img class="imgIndex" ng-src="data:image/png;base64,{{d.image}}"></a>
                </div>
                <div class="postScore">{{d.upvotes - d.downvotes}} HP</div>
            </div>
        </div>
    </div>

4 个答案:

答案 0 :(得分:3)

您的解决方案很慢,因为您从云存储中下载图像并在自己的服务器上提供这些图像。下载和上传会延迟,使用base64编码数据会产生约33%的开销,而且您的服务器在提供图像方面也很紧张,而不是专注于提供网站内容。

正如许多评论所指出的那样,最佳实践解决方案是使用图像的公共URL,如下所示:

function getPublicUrl (filename) {
  return "https://storage.googleapis.com/${CLOUD_BUCKET}/${filename}";
}

通过使用公开网址,您可以直接通过Cloud Storage 利用Google的全球服务基础架构提供服务。并且应用程序不必响应图像请求,从而为其他请求释放CPU周期。

如果您不希望机器人使用上述方法抓取您的图片,Google建议您使用robots.txt文件阻止访问您的图片。

答案 1 :(得分:1)

  1. 在优化之前,您最好收集一些数据,我将在以下代码段中显示一些
  2. 看起来base64_encode(contents)可能会耗费大量CPU,您的逻辑似乎反复这样做。这是猜测,你自己找到它的真正瓶颈
  3. 其他建议可能会减少改进,但这将会产生很大影响(gzip \ CDN \ http2 \ loadbalance ...)
  4. 优化数据收集 - 服务器端,哪个操作花费了太多时间

    &#13;
    &#13;
    router.post('/images', function(req, res, next) {
      var d = new Date()
      var image = bucket.file(req.body.image);
      image.download(function(err, contents) {
        console.log('download:' + new Date() - d)
        if (err) {
          console.log(err);
        } else {
          var resultImage = base64_encode(contents);
          console.log('base64_encode:' + new Date() - d)
          var index = req.body.index;
          var returnObject = {
            image: resultImage,
            index: index
          }
          res.send(returnObject);
        }
      });
    });
    &#13;
    &#13;
    &#13;

    优化数据收集 - 客户端()

    chrome debug bar

    免除使用base64_encode(contents)

    &#13;
    &#13;
    $scope.getDataset = function() {
    
      fb.orderByChild('id').startAt(_start).limitToFirst(_n).once("value", function(dataSnapshot) {
    
        dataSnapshot.forEach(function(childDataSnapshot, index) {
          _start = childDataSnapshot.child("id").val() + 1;
    
          var post = childDataSnapshot.val();
          getImageBase64(post.image)
            .then((image) => {
              post.image = image;
              $scope.data[index] = post;
              $scope.$apply();
              firstElementsLoaded = true;
            })
        })
      });
    
      function getImageBase64(image1) {
        //without help of server, this will make your app faster
        //network reduced
        //server calculation reduced
        if (CanIUseBucktAndBase64Here) {
          return new Promise((reslove, reject) {
            var image = bucket.file(image1);
            image.download(function(err, contents) {
              if (err) {
                reject(err);
              } else {
                //use worker thread might gain better performance
                var resultImage = base64_encode(contents);
                resolve(resultImage)
              }
            });
          })
        }
        //with help of server
        return $.ajax({
            type: "POST",
            url: "images",
            data: image1,
          })
          .then(result => result.image)
      }
    };
    &#13;
    &#13;
    &#13;

    每次都避免下载

    &#13;
    &#13;
    //------------load all to local suit for less images----------
    // if you have many images and you can use cheaper cache like file cache
    
    //--init.js download all images, run only once
    downloadAll()
    
    //--server.js
    //when image updated, let server know and flush cache
    server.get('/imageupdated', (req, res) => {
      downfile(req.params.imgid)
      res.send('got it')
    })
    
    //form cache first
    server.post('/image', (req, res) => {
      memcache.get(req.body.imgid)
        .then((content) => {
          if (!content) return downfile(req.body.imgid)
          res.send({
            content
          })
          return true
        })
        .then((content) => {
          if (content === true) return
          res.send({
            content
          })
        })
    })
    
    server.listen()
    
    
    //--common.js download file and cache to memcache
    function downfile(imgid) {
      var base64 = ''
      return bucket.download(imgid)
        .then((file) => {
          base64 = base64(file)
          return memcache.set(imgid, base64)
        })
        .then(() => {
          return base64
        })
    }
    //downfileBatch
    async function downfileBatch(skip, limit) {
      return cloudDrive.getImages(skip, limit)
        .then((list) => {
          return Promise.all(list.map())
        })
    }
    //down load all images
    async function downloadAll() {
      var i = 0,
        limit = 5
      while (true) {
        var list = await downfileBatch(i, limit)
        if (list.length < limit) {} else {
          i += limit
        }
      }
      return true
    }
    &#13;
    &#13;
    &#13;

答案 2 :(得分:-1)

优化代码的最简单方法是向服务器端发送单个ajax请求,而不是为每个映像执行ajax请求。

从循环中删除ajax调用。循环遍历集合,收集需要发送到阵列中的服务器的数据,然后通过单个ajax请求发送它。这会加快速度。

此外,请确保修改服务器端POST处理程序以便它可以处理数组,您将从客户端传递。

答案 3 :(得分:-2)

我不确定如何提高传送文件的速度,但是它们出现故障的问题是因为它们是异步的。基本上发生的事情是你告诉服务器给你一堆文件然后你等待。一旦服务器将它们发送给您,您就可以处理它们。但是你不知道他们进来的顺序。您需要做的是跟踪他们到达的顺序。这样做的方法是通过某种方式跟踪每个帖子的信息。 例如,假设你有

var arr = new Array(10);
for (var i = 0 ; i < arr.length; i++){
  $.ajax({
    url:____,
    type:"GET" (or whatever type you want),
    data: _____,
    context: {index: i}
    success : function(data){
                 arr[this.index] = data
              }
  })
}

这应该正确设置值。语法可能有点偏,但我相信这是以正确的顺序设置它们的正确想法。重要的是设置上下文,这将设置&#34;这个&#34;在成功处理程序中等于