Knockout.js ช้าอย่างไม่น่าเชื่อภายใต้ชุดข้อมูลกึ่งใหญ่


86

ฉันเพิ่งเริ่มใช้ Knockout.js (อยากลองใช้เสมอ แต่ตอนนี้ฉันมีข้อแก้ตัว!) - อย่างไรก็ตามฉันพบปัญหาประสิทธิภาพการทำงานที่แย่มากเมื่อผูกตารางกับชุดที่ค่อนข้างเล็ก ข้อมูล (ประมาณ 400 แถวหรือมากกว่านั้น)

ในรุ่นของฉันฉันมีรหัสต่อไปนี้:

this.projects = ko.observableArray( [] ); //Bind to empty array at startup

this.loadData = function (data) //Called when AJAX method returns
{
   for(var i = 0; i < data.length; i++)
   {
      this.projects.push(new ResultRow(data[i])); //<-- Bottleneck!
   }
};

ปัญหาคือการforวนรอบด้านบนใช้เวลาประมาณ 30 วินาทีหรือประมาณนั้นโดยมีประมาณ 400 แถว อย่างไรก็ตามหากฉันเปลี่ยนรหัสเป็น:

this.loadData = function (data)
{
   var testArray = []; //<-- Plain ol' Javascript array
   for(var i = 0; i < data.length; i++)
   {
      testArray.push(new ResultRow(data[i]));
   }
};

จากนั้นการforวนซ้ำจะเสร็จสิ้นในพริบตา กล่าวอีกนัยหนึ่งpushวิธีการของobservableArrayวัตถุของ Knockout นั้นช้าอย่างไม่น่าเชื่อ

นี่คือแม่แบบของฉัน:

<tbody data-bind="foreach: projects">
    <tr>
       <td data-bind="text: code"></td>
       <td><a data-bind="projlink: key, text: projname"></td>
       <td data-bind="text: request"></td>
       <td data-bind="text: stage"></td>
       <td data-bind="text: type"></td>
       <td data-bind="text: launch"></td>
       <td><a data-bind="mailto: ownerEmail, text: owner"></a></td>
    </tr>
</tbody>

คำถามของฉัน:

  1. นี่เป็นวิธีที่ถูกต้องในการผูกข้อมูลของฉัน (ซึ่งมาจากเมธอด AJAX) กับคอลเล็กชันที่สังเกตได้หรือไม่
  2. ฉันคาดว่าpushจะทำการคำนวณซ้ำอย่างหนักทุกครั้งที่ฉันเรียกมันเช่นอาจจะสร้างวัตถุ DOM ที่ถูกผูกไว้ใหม่ มีวิธีใดที่จะชะลอการคำนวณใหม่นี้หรืออาจผลักดันรายการทั้งหมดของฉันในคราวเดียว?

ฉันสามารถเพิ่มรหัสเพิ่มเติมได้หากจำเป็น แต่ฉันค่อนข้างมั่นใจว่านี่คือสิ่งที่เกี่ยวข้อง ส่วนใหญ่ฉันแค่ทำตามแบบฝึกหัด Knockout จากเว็บไซต์

อัพเดท:

ตามคำแนะนำด้านล่างฉันได้อัปเดตรหัสของฉันแล้ว:

this.loadData = function (data)
{
   var mappedData = $.map(data, function (item) { return new ResultRow(item) });
   this.projects(mappedData);
};

อย่างไรก็ตามthis.projects()ยังคงใช้เวลาประมาณ 10 วินาทีสำหรับ 400 แถว ฉันยอมรับว่าฉันไม่แน่ใจว่าสิ่งนี้จะเร็วแค่ไหนหากไม่มีสิ่งที่น่าพิศวง (เพียงแค่เพิ่มแถวผ่าน DOM) แต่ฉันรู้สึกว่ามันจะเร็วกว่า 10 วินาทีมาก

อัปเดต 2:

ตามคำแนะนำอื่น ๆ ด้านล่างฉันให้jQuery.tmplยิง (ซึ่ง KnockOut สนับสนุน) และเครื่องมือสร้างเทมเพลตนี้จะวาดประมาณ 400 แถวในเวลาเพียง 3 วินาที นี่ดูเหมือนจะเป็นแนวทางที่ดีที่สุดซึ่งไม่ใช่วิธีแก้ปัญหาที่จะโหลดข้อมูลเพิ่มเติมแบบไดนามิกเมื่อคุณเลื่อน


1
คุณใช้การผูก foreach ที่น่าพิศวงหรือการผูกแม่แบบกับ foreach ฉันแค่สงสัยว่าการใช้เทมเพลตและรวม jquery tmpl แทนเอ็นจินเทมเพลตเนทีฟอาจสร้างความแตกต่างได้หรือไม่
madcapnmckay

1
@MikeChristensen - สิ่งที่น่าพิศวงมีเอ็นจิ้นเทมเพลตเนทีฟของตัวเองที่เชื่อมโยงกับการผูก (foreach, with) นอกจากนี้ยังรองรับเอนจิ้นเทมเพลตอื่น ๆ ได้แก่ jquery.tmpl อ่านที่นี่สำหรับรายละเอียดเพิ่มเติม ฉันยังไม่ได้ทำการเปรียบเทียบกับเอ็นจิ้นอื่นเลยไม่รู้ว่าจะช่วยได้ไหม อ่านความคิดเห็นก่อนหน้าของคุณใน IE7 คุณอาจต้องดิ้นรนเพื่อให้ได้ประสิทธิภาพที่คุณต้องการ
madcapnmckay

2
เมื่อพิจารณาว่าเราเพิ่งได้ IE7 เมื่อไม่กี่เดือนที่ผ่านมาฉันคิดว่า IE9 จะเปิดตัวในช่วงฤดูร้อนปี 2019 โอ้เราทุกคนก็ใช้ WinXP เหมือนกัน .. Blech
Mike Christensen

1
ps เหตุผลที่ดูเหมือนช้าคือคุณกำลังเพิ่ม 400 รายการในอาร์เรย์ที่สังเกตได้ทีละรายการ สำหรับการเปลี่ยนแปลงทุกครั้งที่สังเกตได้มุมมองจะต้องได้รับการแสดงผลใหม่สำหรับทุกสิ่งที่ขึ้นอยู่กับอาร์เรย์นั้น สำหรับเทมเพลตที่ซับซ้อนและรายการจำนวนมากที่ต้องเพิ่มนั่นเป็นค่าใช้จ่ายจำนวนมากเมื่อคุณสามารถอัปเดตอาร์เรย์ทั้งหมดพร้อมกันโดยตั้งค่าเป็นอินสแตนซ์อื่น อย่างน้อยการเรนเดอร์จะเสร็จสิ้นหนึ่งครั้ง
Jeff Mercado

1
ฉันพบวิธีที่เร็วกว่าและเรียบร้อย (ไม่มีอะไรนอกกรอบ) ใช้valueHasMutatedมัน ตรวจสอบคำตอบว่าคุณมีเวลาหรือไม่
เด็ดสุด

คำตอบ:


16

ตามที่แนะนำในความคิดเห็น.

สิ่งที่น่าพิศวงมีเครื่องมือแม่แบบดั้งเดิมของตัวเองที่เชื่อมโยงกับการผูก (foreach, with) นอกจากนี้ยังรองรับเอนจิ้นเทมเพลตอื่น ๆ ได้แก่ jquery.tmpl อ่านที่นี่สำหรับรายละเอียดเพิ่มเติม ฉันยังไม่ได้ทำการเปรียบเทียบกับเอ็นจิ้นอื่นเลยไม่รู้ว่าจะช่วยได้ไหม อ่านความคิดเห็นก่อนหน้าของคุณใน IE7 คุณอาจต้องดิ้นรนเพื่อให้ได้ประสิทธิภาพที่คุณต้องการ

นอกจากนี้ KO ยังรองรับเอ็นจิ้น js templating ใด ๆ หากมีคนเขียนอะแดปเตอร์สำหรับมัน คุณอาจต้องการที่จะลองคนอื่น ๆ ออกมี jQuery tmpl เป็นเพราะถูกแทนที่ด้วยJsRender


ฉันจะสมบูรณ์แบบมากขึ้นด้วยjquery.tmplดังนั้นฉันจะใช้มัน ฉันอาจตรวจสอบเครื่องยนต์อื่น ๆ และเขียนของตัวเองถ้าฉันมีเวลาพิเศษ ขอบคุณ!
Mike Christensen

1
@MikeChristensen - คุณยังใช้data-bindคำสั่งในเทมเพลต jQuery ของคุณหรือคุณใช้ไวยากรณ์ $ {code}
ericb

@ericb - ด้วยรหัสใหม่ฉันใช้${code}ไวยากรณ์และเร็วกว่ามาก ฉันยังพยายามทำให้ Underscore.js ทำงาน แต่ยังไม่มีโชค ( <% .. %>ไวยากรณ์รบกวน ASP.NET) และดูเหมือนจะยังไม่มีการรองรับ JsRender
Mike Christensen

1
@MikeChristensen - โอเคแล้วนี่ก็สมเหตุสมผลแล้ว เอ็นจินเทมเพลตเนทีฟของ KO ไม่จำเป็นต้องไม่มีประสิทธิภาพเสมอไป เมื่อคุณใช้ไวยากรณ์ $ {code} คุณจะไม่ได้รับการผูกข้อมูลใด ๆ กับองค์ประกอบเหล่านั้น (ซึ่งช่วยเพิ่มความสมบูรณ์แบบ) ดังนั้นหากคุณเปลี่ยนคุณสมบัติของ a ResultRowมันจะไม่อัปเดต UI (คุณจะต้องอัปเดตprojectsobservableArray ซึ่งจะบังคับให้มีการแสดงผลตารางของคุณอีกครั้ง) $ {} จะเป็นประโยชน์อย่างแน่นอนหากข้อมูลของคุณค่อนข้างอ่านอย่างเดียว
ericb

4
เนโครแมนซี่! jquery.tmplไม่มีการพัฒนาอีกต่อไป
Alex Larzelere

50

โปรดดู: Knockout.js Performance Gotcha # 2 - Manipulating observableArrays

รูปแบบที่ดีกว่าคือการได้รับการอ้างอิงไปยังอาร์เรย์พื้นฐานของเรากดไปที่มันแล้วเรียก. valueHasMutated () ตอนนี้สมาชิกของเราจะได้รับการแจ้งเตือนเพียงครั้งเดียวที่ระบุว่าอาร์เรย์มีการเปลี่ยนแปลง


13

ใช้เลขหน้ากับ KO นอกเหนือจากการใช้ $ .map

ฉันมีปัญหาเดียวกันกับชุดข้อมูลขนาดใหญ่ 1,400 ระเบียนจนกระทั่งฉันใช้การเพจกับสิ่งที่น่าพิศวง การใช้$.mapเพื่อโหลดบันทึกสร้างความแตกต่างอย่างมาก แต่เวลาในการเรนเดอร์ DOM ยังคงน่ากลัว จากนั้นฉันลองใช้การแบ่งหน้าและนั่นทำให้ชุดข้อมูลของฉันรวดเร็วและเป็นมิตรกับผู้ใช้มากขึ้น ขนาดหน้า 50 ทำให้ชุดข้อมูลล้นน้อยลงมากและลดจำนวนองค์ประกอบ DOM ลงอย่างมาก

มันง่ายมากที่จะทำกับ KO:

http://jsfiddle.net/rniemeyer/5Xr2X/


11

KnockoutJS มีบทช่วยสอนที่ยอดเยี่ยมโดยเฉพาะอย่างยิ่งเกี่ยวกับการโหลดและบันทึกข้อมูล

ในกรณีของพวกเขาพวกเขาดึงข้อมูลโดยใช้getJSON()ซึ่งเร็วมาก จากตัวอย่าง:

function TaskListViewModel() {
    // ... leave the existing code unchanged ...

    // Load initial state from server, convert it to Task instances, then populate self.tasks
    $.getJSON("/tasks", function(allData) {
        var mappedTasks = $.map(allData, function(item) { return new Task(item) });
        self.tasks(mappedTasks);
    });    
}

1
การปรับปรุงครั้งใหญ่แน่นอน แต่self.tasks(mappedTasks)ใช้เวลาประมาณ 10 วินาทีในการรัน (มี 400 แถว) ฉันรู้สึกว่านี่ยังไม่เป็นที่ยอมรับ
Mike Christensen

ฉันยอมรับว่า 10 วินาทีนั้นไม่สามารถยอมรับได้ การใช้ knockoutjs ฉันไม่แน่ใจว่าอะไรดีกว่าแผนที่ดังนั้นฉันจะชอบคำถามนี้และดูคำตอบที่ดีกว่า
deltree

1
ตกลง. คำตอบนั้นสมควรได้รับ+1สำหรับทั้งการทำให้โค้ดของฉันง่ายขึ้นและเพิ่มความเร็วอย่างมาก บางทีอาจมีคนอธิบายรายละเอียดเพิ่มเติมว่าคอขวดคืออะไร
Mike Christensen

9

ให้KoGridดู มันจัดการการแสดงผลแถวของคุณอย่างชาญฉลาดเพื่อให้มีประสิทธิภาพมากขึ้น

หากคุณพยายามผูก 400 แถวเข้ากับตารางโดยใช้การforeachผูกคุณจะมีปัญหาในการผลักดันจำนวนมากผ่าน KO ไปยัง DOM

KO ทำสิ่งที่น่าสนใจมาก ๆ โดยใช้การforeachโยงซึ่งส่วนใหญ่เป็นการดำเนินการที่ดีมาก แต่พวกมันจะเริ่มแยกย่อยจากความสมบูรณ์แบบเมื่อขนาดของอาร์เรย์ของคุณเติบโตขึ้น

ฉันเคยไปตามถนนมืดอันยาวนานในการพยายามผูกชุดข้อมูลขนาดใหญ่เข้ากับตาราง / กริดและคุณต้องแยก / จัดหน้าข้อมูลในเครื่อง

KoGridทำทั้งหมดนี้ สร้างขึ้นเพื่อแสดงเฉพาะแถวที่ผู้ดูสามารถมองเห็นได้บนเพจจากนั้นจึงจำลองแถวอื่น ๆ จนกว่าจะจำเป็น ฉันคิดว่าคุณจะพบว่ามันสมบูรณ์แบบจาก 400 รายการที่ดีกว่าที่คุณพบ


1
ดูเหมือนว่าจะเสียอย่างสมบูรณ์ใน IE7 (ไม่มีตัวอย่างใดที่ใช้งานได้) มิฉะนั้นจะดีมาก!
Mike Christensen

ดีใจที่ได้ตรวจสอบ - KoGrid ยังอยู่ในระหว่างการพัฒนา อย่างไรก็ตามอย่างน้อยสิ่งนี้ตอบคำถามของคุณเกี่ยวกับ perf หรือไม่?
ericb

1
ได้! เป็นการยืนยันความสงสัยเดิมของฉันว่าเอ็นจิ้นเทมเพลต KO เริ่มต้นค่อนข้างช้า หากคุณต้องการให้ใครเลี้ยงหนูตะเภา KoGrid ให้คุณฉันยินดีที่จะ ดูเหมือนว่าสิ่งที่เราต้องการ!
Mike Christensen

ยี้. ดูดีจริงๆ! น่าเสียดายที่ผู้ใช้แอปพลิเคชันของฉันกว่า 50% ใช้ IE7!
Jim G.

ที่น่าสนใจคือปัจจุบันเราต้องสนับสนุน IE11 อย่างไม่เต็มใจนัก สิ่งต่างๆดีขึ้นในช่วง 7 ปีที่ผ่านมา
MrBoJangles

5

วิธีแก้ปัญหาเพื่อหลีกเลี่ยงการล็อกเบราว์เซอร์เมื่อแสดงอาร์เรย์ขนาดใหญ่มากคือการ 'เค้น' อาร์เรย์เพื่อให้มีการเพิ่มองค์ประกอบเพียงไม่กี่รายการในแต่ละครั้งโดยมีการนอนหลับระหว่างกัน นี่คือฟังก์ชั่นที่จะทำสิ่งนั้น:

function throttledArray(getData) {
    var showingDataO = ko.observableArray(),
        showingData = [],
        sourceData = [];
    ko.computed(function () {
        var data = getData();
        if ( Math.abs(sourceData.length - data.length) / sourceData.length > 0.5 ) {
            showingData = [];
            sourceData = data;
            (function load() {
                if ( data == sourceData && showingData.length != data.length ) {
                    showingData = showingData.concat( data.slice(showingData.length, showingData.length + 20) );
                    showingDataO(showingData);
                    setTimeout(load, 500);
                }
            })();
        } else {
            showingDataO(showingData = sourceData = data);
        }
    });
    return showingDataO;
}

ขึ้นอยู่กับกรณีการใช้งานของคุณซึ่งอาจส่งผลให้มีการปรับปรุง UX ครั้งใหญ่เนื่องจากผู้ใช้อาจเห็นเฉพาะแถวแรกก่อนที่จะต้องเลื่อน


ฉันชอบโซลูชันนี้ แต่แทนที่จะใช้ setTimeout ทุกครั้งฉันขอแนะนำให้เรียกใช้ setTimout ทุกๆ 20 ครั้งหรือมากกว่านั้นเพราะทุกครั้งก็ใช้เวลาโหลดนานเกินไป ฉันเห็นว่าคุณกำลังทำเช่นนั้นกับ +20 แต่มันก็ไม่ชัดเจนสำหรับฉันในตอนแรก
charlierlee

5

การใช้ประโยชน์จาก push () การยอมรับข้อโต้แย้งของตัวแปรทำให้เกิดประสิทธิภาพที่ดีที่สุดในกรณีของฉัน 1300 แถวกำลังโหลดเป็นเวลา 5973ms (~ 6 วินาที) ด้วยการเพิ่มประสิทธิภาพนี้เวลาในการโหลดลดลงเหลือ 914ms (<1 วินาที)
ซึ่งดีขึ้น 84.7%!

ข้อมูลเพิ่มเติมที่การ ผลักดันรายการไปยัง ObservableArray

this.projects = ko.observableArray( [] ); //Bind to empty array at startup

this.loadData = function (data) //Called when AJAX method returns
{
   var arrMappedData = ko.utils.arrayMap(data, function (item) {
       return new ResultRow(item);
   });
   //take advantage of push accepting variable arguments
   this.projects.push.apply(this.projects, arrMappedData);
};

4

ฉันรับมือกับข้อมูลจำนวนมหาศาลที่เข้ามาสำหรับฉันvalueHasMutatedได้ผลเหมือนมีเสน่ห์

ดูรุ่น:

this.projects([]); //make observableArray empty --(1)

var mutatedArray = this.projects(); -- (2)

this.loadData = function (data) //Called when AJAX method returns
{
ko.utils.arrayForEach(data,function(item){
    mutatedArray.push(new ResultRow(item)); -- (3) // push to the array(normal array)  
});  
};
 this.projects.valueHasMutated(); -- (4) 

หลังจากเรียก(4)ข้อมูลอาร์เรย์จะถูกโหลดลงใน observableArray ที่จำเป็นซึ่งเป็นไปthis.projectsโดยอัตโนมัติ

หากคุณมีเวลาลองดูสิ่งนี้และในกรณีที่มีปัญหาใด ๆ โปรดแจ้งให้เราทราบ

เคล็ดลับที่นี่:โดยการทำเช่นนี้หากในกรณีที่การอ้างอิงใด ๆ (คำนวณเป็นสมาชิก ฯลฯ ) (4)สามารถหลีกเลี่ยงได้ในระดับผลักดันและเราสามารถทำให้พวกเขาดำเนินการที่หนึ่งไปหลังจากเรียก


1
ปัญหาไม่ได้อยู่ที่การโทรมากเกินไปpushปัญหาคือแม้แต่การโทรเพียงครั้งเดียวเพื่อพุชจะทำให้เวลาในการแสดงผลนาน หากอาร์เรย์มีรายการ 1,000 รายการที่ผูกไว้กับ a การforeachกดรายการเดียวจะทำให้เกิดการแสดงผล foreach ทั้งหมดและคุณต้องเสียค่าใช้จ่ายในการแสดงผลครั้งใหญ่
เล็กน้อย

1

วิธีแก้ปัญหาที่เป็นไปได้ร่วมกับการใช้ jQuery.tmpl คือการพุชไอเท็มในแต่ละครั้งไปยังอาร์เรย์ที่สังเกตได้ในลักษณะอะซิงโครนัสโดยใช้ setTimeout

var self = this,
    remaining = data.length;

add(); // Start adding items

function add() {
  self.projects.push(data[data.length - remaining]);

  remaining -= 1;

  if (remaining > 0) {
    setTimeout(add, 10); // Schedule adding any remaining items
  }
}

ด้วยวิธีนี้เมื่อคุณเพิ่มทีละรายการเท่านั้นเบราว์เซอร์ / สิ่งที่น่าพิศวง js อาจใช้เวลาในการจัดการ DOM ตามนั้นโดยที่เบราว์เซอร์ไม่ถูกบล็อกโดยสมบูรณ์เป็นเวลาหลายวินาทีเพื่อให้ผู้ใช้สามารถเลื่อนรายการพร้อมกัน


2
การดำเนินการนี้จะบังคับให้มีการอัปเดต DOM จำนวน N ซึ่งจะทำให้เวลาในการแสดงผลทั้งหมดนานกว่าการทำทุกอย่างพร้อมกัน
Fredrik C

ที่ถูกต้องแน่นอน อย่างไรก็ตามประเด็นก็คือการรวมกันของ N เป็นตัวเลขจำนวนมากและการผลักดันรายการไปยังอาร์เรย์ของโปรเจ็กต์ซึ่งทำให้เกิดการอัปเดตหรือการคำนวณ DOM อื่น ๆ จำนวนมากอาจทำให้เบราว์เซอร์หยุดทำงานและเสนอให้คุณฆ่าแท็บ ด้วยการกำหนดระยะหมดเวลาต่อรายการหรือต่อ 10, 100 หรือจำนวนรายการอื่น ๆ เบราว์เซอร์จะยังคงตอบสนอง
gnab

2
ฉันจะบอกว่านี่เป็นแนวทางที่ผิดในกรณีทั่วไปที่การอัปเดตทั้งหมดจะไม่หยุดเบราว์เซอร์ แต่เป็นสิ่งที่ต้องใช้เมื่ออื่น ๆ ทั้งหมดล้มเหลว สำหรับฉันแล้วดูเหมือนว่าแอปพลิเคชันที่เขียนไม่ดีซึ่งควรแก้ไขปัญหาด้านประสิทธิภาพแทนที่จะทำให้ไม่หยุดนิ่ง
Fredrik C

1
แน่นอนว่ามันเป็นแนวทางที่ผิดในกรณีทั่วไปไม่มีใครไม่เห็นด้วยกับคุณในเรื่องนี้ นี่คือการแฮ็กและเป็นข้อพิสูจน์แนวคิดในการป้องกันไม่ให้เบราว์เซอร์หยุดทำงานหากคุณต้องการดำเนินการกับ DOM จำนวนมาก ฉันต้องการมันเมื่อสองสามปีก่อนเมื่อแสดงรายการตาราง HTML ขนาดใหญ่หลายรายการพร้อมการเชื่อมโยงหลายรายการต่อเซลล์ส่งผลให้มีการประเมินการเชื่อมโยงหลายพันรายการซึ่งแต่ละรายการมีผลต่อสถานะของ DOM จำเป็นต้องมีฟังก์ชันการทำงานชั่วคราวเพื่อตรวจสอบความถูกต้องของการนำแอปพลิเคชันเดสก์ท็อปที่ใช้ Excel มาใช้งานซ้ำเป็นเว็บแอปพลิเคชัน จากนั้นวิธีนี้ก็ทำงานได้อย่างสมบูรณ์แบบ
gnab

ความคิดเห็นส่วนใหญ่ให้คนอื่นอ่านเพื่อไม่ให้คิดว่านี่เป็นวิธีที่ต้องการ ฉันเดาว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่
Fredrik C

1

ฉันได้ทดลองประสิทธิภาพและมีส่วนร่วมสองอย่างที่หวังว่าอาจเป็นประโยชน์

การทดลองของฉันมุ่งเน้นไปที่เวลาในการจัดการ DOM ดังนั้นก่อนที่จะเข้าสู่สิ่งนี้คุณควรทำตามประเด็นด้านบนเกี่ยวกับการผลักเข้าไปในอาร์เรย์ JS ก่อนสร้างอาร์เรย์ที่สังเกตได้

แต่ถ้าเวลาในการจัดการ DOM ยังคงเป็นอุปสรรคอยู่สิ่งนี้อาจช่วยได้:


1: รูปแบบในการห่อสปินเนอร์โหลดรอบการเรนเดอร์ช้าจากนั้นซ่อนโดยใช้ afterRender

http://jsfiddle.net/HBYyL/1/

นี่ไม่ใช่วิธีแก้ไขปัญหาด้านประสิทธิภาพ แต่แสดงให้เห็นว่าความล่าช้าอาจเป็นสิ่งที่หลีกเลี่ยงไม่ได้หากคุณวนซ้ำหลายพันรายการและใช้รูปแบบที่คุณสามารถมั่นใจได้ว่าคุณมีสปินเนอร์โหลดปรากฏขึ้นก่อนการดำเนินการ KO ที่ยาวนานจากนั้นซ่อน หลังจากนั้น ดังนั้นจึงปรับปรุง UX อย่างน้อย

ตรวจสอบให้แน่ใจว่าคุณสามารถโหลดสปินเนอร์ได้:

// Show the spinner immediately...
$("#spinner").show();

// ... by using a timeout around the operation that causes the slow render.
window.setTimeout(function() {
    ko.applyBindings(vm)  
}, 1)

ซ่อนสปินเนอร์:

<div data-bind="template: {afterRender: hide}">

ซึ่งทริกเกอร์:

hide = function() {
    $("#spinner").hide()
}

2: การใช้การรวม html เป็นการแฮ็ก

ฉันจำเทคนิคเก่า ๆ ได้ตั้งแต่ตอนที่ฉันทำงานกับ set top box ด้วย Opera ซึ่งสร้าง UI โดยใช้การจัดการ DOM มันช้าอย่างน่าตกใจดังนั้นวิธีแก้ปัญหาคือการจัดเก็บ HTML จำนวนมากเป็นสตริงและโหลดสตริงโดยการตั้งค่าคุณสมบัติ innerHTML

สิ่งที่คล้ายกันนี้สามารถทำได้โดยใช้การเชื่อม html และการคำนวณที่ได้รับ HTML สำหรับตารางเป็นข้อความขนาดใหญ่จากนั้นนำไปใช้ในครั้งเดียว สิ่งนี้ช่วยแก้ปัญหาด้านประสิทธิภาพได้ แต่ข้อเสียอย่างมากคือการ จำกัด สิ่งที่คุณสามารถทำได้อย่างมากด้วยการผูกภายในแต่ละแถวของตาราง

นี่คือซอที่แสดงวิธีการนี้พร้อมกับฟังก์ชั่นที่สามารถเรียกได้จากในแถวของตารางเพื่อลบรายการในลักษณะที่คลุมเครือเหมือน KO เห็นได้ชัดว่านี่ไม่ดีเท่า KO ที่เหมาะสม แต่ถ้าคุณต้องการประสิทธิภาพที่ชัดเจน (ish) จริงๆนี่เป็นวิธีแก้ปัญหาที่เป็นไปได้

http://jsfiddle.net/9ZF3g/5/


1

หากใช้ IE ให้ลองปิดเครื่องมือ dev

การเปิดเครื่องมือสำหรับนักพัฒนาใน IE จะทำให้การดำเนินการนี้ช้าลงอย่างมาก ฉันกำลังเพิ่ม ~ 1,000 องค์ประกอบในอาร์เรย์ เมื่อเปิดเครื่องมือ dev จะใช้เวลาประมาณ 10 วินาทีและ IE จะหยุดทำงานในขณะที่กำลังเกิดขึ้น เมื่อฉันปิดเครื่องมือ dev การดำเนินการจะดำเนินการทันทีและฉันไม่เห็นการทำงานช้าลงใน IE


0

ฉันสังเกตด้วยว่าเอ็นจินแม่แบบ Knockout js ทำงานช้าลงใน IE ฉันแทนที่ด้วย underscore.js ซึ่งทำงานได้เร็วขึ้น


คุณทำสิ่งนี้ได้อย่างไร?
Stu Harper

@StuHarper ฉันนำเข้าไลบรารีขีดล่างจากนั้นใน main.js ฉันทำตามขั้นตอนที่อธิบายไว้ในส่วนการรวมขีดล่างของknockoutjs.com/documentation/template-binding.html
Marcello

การปรับปรุงนี้เกิดขึ้นกับ IE เวอร์ชันใด
bkwdesign

@bkwdesign ฉันใช้ IE 10, 11
Marcello
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.