2014-09-25 3 views
0

Я построил страницу Visualforce, которая тянет как Контакты, так и Вводы в один вид. Он отлично работает, за исключением того, что требуется 20-25 секунд для загрузки, что, как мы все знаем, УЖАСНОЕ для удобства использования.Как уменьшить время загрузки (Visualforce, Apex, Angular)

Я просмотрел журналы, и похоже, что Apex занимает 70% времени загрузки, а 30% потрачено на часть javascript, и я могу опубликовать журнал, если потребуется.

Примечание: Этот проект был основан на работах Mohit Shrivastav. Около 1/2 пути через проект я решил, что хочу использовать datatables.net вместо Angular для сортировки, так как я все еще изучаю Angular.

Вот контроллер:

public with sharing class recentMqlExplorerController { 
    public String LeadContactList { 
    get; set; 
    } 

    public class ContactLeadWrap { 
    public String id; 
    public String name; 
    public String dateofmql; 
    public String company; 
    public Decimal leadscore; 
    public String country; 
    public String state; 
    public Integer employees; 
    public String ownername; 
    public String leadstatus; 
    public String leadorcontact; 
    public String team; 
    public String url; 

    ContactLeadWrap() { 
     id = ''; 
     name = ''; 
     company = ''; 
     leadscore = 0; 
     country = ''; 
     state = ''; 
     employees = 0; 
     ownername = ''; 
     leadstatus = ''; 
     url = ''; 
     team = ''; 
    } 
    } 

    //Method to bring the list of Contacts and Leads and Serialize Wrapper Object as JSON 
    public static String getlstContactLead() { 
    List <ContactLeadWrap> lstwrap = new List <ContactLeadWrap>(); 
    List <Contact> lstcontact = new List<Contact>(); 
    List <Lead> lstlead = new List<Lead>(); 
    Datetime now = System.now(); 
    Datetime last = now.addDays(-60); 
    Id ownerId = UserInfo.getUserId(); 


    lstcontact = [SELECT Id, FirstName, Name, Date_Became_MQL__c, Account.Name, mkto2__Lead_Score__c, Account.BillingCountry, Account.BillingState, Account.NumberOfEmployees, Owner.Name, z_Lead_Status_at_Convert_TEXT_if_applcbl__c, Account.AOU__r.sub_sub_Team_Picklist__c FROM Contact WHERE (Date_Became_MQL__c > :last AND Owner.Id = :ownerId) OR FirstName = 'westest' LIMIT 20000]; 

    lstlead = [SELECT Id, FirstName, Name, Date_Became_MQL__c, Company, mkto2__Lead_Score__c, Country, State, NumberOfEmployees, Owner.Name, status, z_Lead_Owner_User__r.sub_sub_Team_Picklist__c FROM Lead WHERE (Date_Became_MQL__c > :last AND IsConverted = false AND Owner.Id = :ownerId) OR (FirstName = 'westest' AND IsConverted = false) LIMIT 20000]; 


    String convertedDateofmql = null; 
    Date dateOnly = null; 
    String fullRecordURL = null; 

    for (Contact c: lstcontact) { 
     if (c.Date_Became_MQL__c != null) { 
      convertedDateofmql = c.Date_Became_MQL__c.format('MM/dd/YYYY'); 
     } 
     if (c.z_Lead_Status_at_Convert_TEXT_if_applcbl__c == null) { 
      c.z_Lead_Status_at_Convert_TEXT_if_applcbl__c = 'no status'; 
     } 
     fullRecordURL = URL.getSalesforceBaseUrl().toExternalForm() + '/' + c.Id; 
     ContactLeadWrap cwrap = new ContactLeadWrap(); 
     cwrap.id = c.id; 
     cwrap.name = c.name; 
     cwrap.url = fullRecordURL; 
     cwrap.dateofmql = convertedDateofmql; 
     cwrap.company = c.Account.Name; 
     cwrap.leadscore = c.mkto2__Lead_Score__c; 
     cwrap.country = c.Account.BillingCountry; 
     cwrap.state = c.Account.BillingState; 
     cwrap.employees = c.Account.NumberOfEmployees; 
     cwrap.ownername = c.Owner.Name; 
     cwrap.leadstatus = c.z_Lead_Status_at_Convert_TEXT_if_applcbl__c; 
     cwrap.leadorcontact = 'Contact'; 
     cwrap.team = c.Account.AOU__r.sub_sub_Team_Picklist__c; 
     lstwrap.add(cwrap); 
    } 
    for (Lead l: lstlead) { 
     if (l.Date_Became_MQL__c != null) { 
      convertedDateofmql = l.Date_Became_MQL__c.format('MM/dd/YYYY'); 
     } 
     fullRecordURL = URL.getSalesforceBaseUrl().toExternalForm() + '/' + l.Id; 
     ContactLeadWrap lwrap = new ContactLeadWrap(); 
     lwrap.id = l.id; 
     lwrap.name = l.name; 
     lwrap.url = fullRecordURL; 
     lwrap.dateofmql = convertedDateofmql; 
     lwrap.company = l.Company; 
     lwrap.leadscore = l.mkto2__Lead_Score__c; 
     lwrap.country = l.Country; 
     lwrap.state = l.State; 
     lwrap.employees = l.NumberOfEmployees; 
     lwrap.ownername = l.Owner.Name; 
     lwrap.leadstatus = l.status; 
     lwrap.leadorcontact = 'Lead'; 
     lwrap.team = l.z_Lead_Owner_User__r.sub_sub_Team_Picklist__c; 
     lstwrap.add(lwrap); 
    } 
    return JSON.serialize(lstwrap); 
    } 

    public class getInformation { 

    } 
} 

Вот страница:

<apex:page standardStylesheets="false" sidebar="false" showHeader="false" docType="html-5.0" controller="recentMqlExplorerController"> 
    <html xmlns:ng="http://angularjs.org" ng-app="hello" lang="en"> 
     <head> 
     <meta charset="utf-8"></meta> 
     <meta http-equiv="X-UA-Compatible" content="IE=edge"></meta> 
     <title>MQL Explorer</title> 
     <meta name="description" content=""></meta> 
     <meta name="viewport" content="width=device-width"></meta> 
      <link rel="stylesheet" href="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/sass-bootstrap/dist/css/bootstrap.css')}"/> 
      <link rel="stylesheet" href="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/styles/main.css')}"/> 
      <link type='text/css' href='//fonts.googleapis.com/css?family=Open+Sans:300italic,400,300' rel='stylesheet'/> 
     </head> 
     <body> 
      <!-- =========== Binding Controller to Body of Page ============= --> 
      <div class="jumbotron ribbon"> 
      <h2>Hello {!$User.FirstName}:</h2> <h4> Welcome to the Recent MQL Dashboard</h4> 
     </div> 
     <div class="jumbotron banner row"> 
      <span class="chevron"><i class="fa fa-chevron-down fa-1x"></i></span> 
      <div class="jumbotron jbot"></div> 
        <div class="dashboard"> 
        </div> 
        <div class="dashboard-shadow"></div> 
     </div> 
      <div ng-controller="ctrlRead" class="container table-container"> 
       <div class="table-container-header"> 
         <h4>Qualified Leads and Contacts</h4> 
       </div> 
       <table id="dashboard" class="table-borders display responsive" width="100%"> 
       <thead> 
        <tr role="row" class="tableFilters"> 
         <th>Search by Name</th> 
         <th>From when?</th> 
         <th>Search by Company</th> 
         <th></th> 
         <th></th> 
         <th></th> 
         <th></th> 
         <th id="owner">Search by Owner</th> 
         <th>What Status?</th> 
         <!-- <th>What Type?</th> --> 
         <th>What Team?</th> 
        </tr> 
        <tr role="row" class="tableHeader"> 
         <th scope="col" class="name">Name</th> 
         <th scope="col" class="dateofmql" width="250px">Date of MQL</th> 
         <th scope="col" class="company">Company</th> 
         <th scope="col" class="leadscore">Score</th> 
         <th scope="col" class="country">Country</th> 
         <th scope="col" class="state">State</th> 
         <th scope="col" class="employees">EE#</th> 
         <th scope="col" class="ownername">Owner Name</th> 
         <th scope="col" class="leadstatus">Lead Status</th> 
         <!-- <th scope="col" class="leadorcontact">Type</th> --> 
         <th scope="col" class="team">Sales Team</th> 
        </tr> 
       </thead> 
       <tbody class="table"> 
         <tr ng-repeat="item in pagedItems[currentPage] | orderBy:sortingOrder:reverse"> 
          <th><apex:outputlink style="text-decoration: underline; color: #01B2E4;" target="_blank" value="{{item.url}}">{{item.name}}</apex:outputlink></th> 
          <td>{{item.dateofmql}}</td> 
          <td>{{item.company}}</td> 
          <td>{{item.leadscore}}</td> 
          <td>{{item.country}}</td> 
          <td>{{item.state}}</td> 
          <td>{{item.employees}}</td> 
          <td>{{item.ownername}}</td> 
          <td>{{item.leadstatus}}</td> 
          <td>{{item.team}}</td> 
         </tr> 
        </tbody> 
       </table> 
      </div> 

     <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/angular/angular.min.js')}"/> 
      <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/jquery/jquery.min.js')}"/> 
      <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/jquery/jquery-ui.min.js')}"/> 
      <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/jquery/jquery.dataTables.min.js')}"/> 
      <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/jquery/dataTables.tableTools.min.js')}"/> 
      <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/jquery/dataTables.responsive.min.js')}"/> 
      <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/jquery/jquery.dataTables.columnFilter-min.js')}"/> 
      <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/bower_components/angular-force/ngForce.min.js')}"/> 
      <script src="{!URLFOR($Resource.smbMqlHunterAppMarkIiiDEV, '/scripts/app-min.js')}"/> 
      <script type="text/javascript"> 
       'use strict'; 
       <!-- Name your application --> 
       var myapp = angular.module('hello', []); 
       var sortingOrder = 'name'; 
       <!-- Define Controller --> 
       var contrl=myapp.controller('ctrlRead', function ($scope, $filter) { 
       <!--- Initialize Scope Variables ---> 
       $scope.sortingOrder = sortingOrder; 
       $scope.reverse = false; 
       $scope.filteredItems = []; 
       $scope.groupedItems = []; 
       $scope.itemsPerPage = 60000; 
       $scope.pagedItems = []; 
       $scope.currentPage = 0; 
       $scope.items ={!lstContactLead}; 
       var searchMatch = function (haystack, needle) { 
        if (!needle) { 
         return true; 
        } 
        return haystack.toLowerCase().indexOf(needle.toLowerCase()) !== -1; 
       }; 
       //Initialize the Search Filters 
       $scope.search = function() { 
        $scope.filteredItems = $filter('filter')($scope.items, function (item) { 
         for (var attr in item) { 
          if (searchMatch(item[attr], $scope.query)) 
           return true; 
         } 
         return false; 
        }); 
        // Define Sorting Order 
        if ($scope.sortingOrder !== '') { 
         $scope.filteredItems = $filter('orderBy')($scope.filteredItems, $scope.sortingOrder, $scope.reverse); 
        } 
        $scope.currentPage = 0; 

        // Group by pages 
        $scope.groupToPages(); 
       }; 
       // Calculate Total Number of Pages based on Records Queried 
       $scope.groupToPages = function() { 
        $scope.pagedItems = []; 
        for (var i = 0; i < $scope.filteredItems.length; i++) { 
         if (i % $scope.itemsPerPage === 0) { 
          $scope.pagedItems[Math.floor(i/$scope.itemsPerPage)] = [$scope.filteredItems[i]]; 
         } else { 
          $scope.pagedItems[Math.floor(i/$scope.itemsPerPage)].push($scope.filteredItems[i]); 
         } 
        } 
       }; 

       $scope.range = function (start, end) { 
        var ret = []; 
        if (!end) { 
         end = start; 
         start = 0; 
        } 
        for (var i = start; i < end; i++) { 
         ret.push(i); 
        } 
        return ret; 
       }; 

        $scope.prevPage = function() { 
         if ($scope.currentPage > 0) { 
          $scope.currentPage--; 
         } 
        }; 

        $scope.nextPage = function() { 
         if ($scope.currentPage < $scope.pagedItems.length - 1) { 
          $scope.currentPage++; 
         } 
        }; 
        $scope.setPage = function() { 
         $scope.currentPage = this.n; 
        }; 
        // functions have been describe process the data for display 
        $scope.search(); 

        // change sorting order 
        $scope.sort_by = function (newSortingOrder) { 
         if ($scope.sortingOrder == newSortingOrder) 
          $scope.reverse = !$scope.reverse; 
         $scope.sortingOrder = newSortingOrder; 

         // icon setup 
         $('th i').each(function() { 
          // icon reset 
          $(this).removeClass().addClass('icon-sort'); 
         }); 
         if ($scope.reverse) 
          $('th.' + new_sorting_order + ' i').removeClass().addClass('icon-chevron-up'); 
         else 
          $('th.' + new_sorting_order + ' i').removeClass().addClass('icon-chevron-down'); 
        }; 
       }); 
       contrl.$inject = ['$scope', '$filter']; 
      </script> 
     </body> 
    </html> 
</apex:page> 

ответ

2

Пожалуйста, обратите внимание на ниже указаниями отдела продаж может быть полезным для улучшения производительности страницы.

Большие размеры страниц напрямую влияют на время загрузки. Чтобы улучшить время загрузки страницы Visualforce:

Кэш любых данных, к которым часто обращаются, например, значок.

Избегайте запросов SOQL в ваших методах getter-контроллера Apex.

Снизить количество записей, отображаемых на странице по:

Предельной данные, возвращающиеся из SOQL вызовов в контроллерах Apex. Например, при использовании и утверждение в вашей ИНЕКЕ или удаление нулевых результатов

Воспользовавшись пагинации с контроллером списка, чтобы представить меньше записей на страницу

«Ленивые нагрузки» объекты Apex, чтобы уменьшить время запроса.

Рассмотрите возможность перемещения любого JavaScript за пределами тега и поместить его в тег непосредственно перед закрывающим тегом. Тег помещает JavaScript прямо перед элементом закрытия; таким образом, Visualforce пытается загрузить JavaScript перед любым другим контентом на странице. Тем не менее, вы должны переместить JavaScript только в нижней части страницы, если вы уверены, что не имеет никаких негативных последствий для вашей страницы. Например, фрагменты кода JavaScript, требующие обработчиков document.write или обработчиков событий, должны оставаться в элементе.

Во всех случаях страницы Visualforce должны быть менее 15 МБ.

С уважением,

Нэвин

http://www.autorabit.com

1

Просто, принимая беглый взгляд в код следующие мои наблюдения.

1) Вы используете слишком много скриптов, хранящихся в ваших скриптах, таких как угловые, jquery, Bootstrap и т. Д. Используя эти многие скрипты, вы делаете временную задержку. Не уверены в ваших требованиях, но ищите способ ограничить использование внешних скриптов.

2) Не использовать теги Salesforce. Почти полная страница основана на JAVA, которая вставляется в теги apex. Например, используйте таблицы apex вместо таблиц tr и td.

Использование стандартных функций из окна позволит уменьшить время загрузки страницы и попытаться использовать собственные сценарии Salesforce.

3) Я бы даже предложил использовать собственный скрипт вместо начальной загрузки, если вы не используете много тегов. Когда в Salesforce попытайтесь сохранить внешний вид Salesforce, который даст наилучшие результаты.

Отказ от ответственности. Это общие рекомендации по оптимизации загрузки страниц, хотя конкретные требования могут вынуждать использовать собственные сценарии.

Ashish

Смежные вопросы