0

I'm currently modifying a open source project (link) to fit my need.

my English is bad, maybe it will be clearer if you can click on the link page, it will take half of minute to load, browser may seems to be freeze for a moment.

this page uses slickgrid , when hovering mouse over table rows , it will render details of that row on a fixed-position layer on page(the bottom left). there is only one such detail layer on the page, when you move your mouse to another row, this layer will change to show details of that row. following code is how it achieve this :

this.grid.onMouseEnter.subscribe( function (e) {})  // use slickgrid to set event listeners
// inside the handler function
from event e, get the row number row.rc 
// then calls the staticOverlayDetails function do the actual  work. it will renders the presentation layer.
window.setTimeout(function(){staticOverlayDetails(rc.row);}, 30);

so this staticOverlayDetails function will render the layer ( a div element ) to show the detail of row number rc.row, which is where mouse cursor is at.

I want to collect all the rendered result layer html code so I can combine them into a single page for easy read. that means, I want to hover my mouse on row one, wait for layer to be rendered, copy and save the div element, then move mouse to the next row , wait for the layer to be rendered with this new row , ...repeat until all row are done.

function staticOverlayDetails pseudo code:

function staticOverlayDetails (rown) {
     //step 1:generate html text structure for the row, but leaves an element blank, this element is a text description for the row. the text will be loaded from a txt file
     ...
     ...

     // html_text contains an `div` for description text which is currently empty,  the text need to be fetched from a text file url, the text file name is based on the content of row. for the purpose of when the text is fetched, the callingback function need to know where to insert and avoid insert wrongly ( if the mouse has already moved to another row, the layer is showing details of another row, so the description text mismatch), so here it set a random string as the unique id of the description `div`, so later the `insert` function can use the id string as selector to insert text.
     description_selector = random_id
     html_text= html_code_generated

     //step 2:
     // this function fetches a  , setting a callback function `insert` to insert the content.
     url=generate text file url from row content
     load_description( url, description_selector )
     //step 3: present html
     $(fixed-layer).html(txt)
     //at this time , the description div is blank. the callback function will insert content into div when fetched.
}

function load_description (url, description_selector) {

     function insert ( descrp_text ) {
          $(description_selector).html(descrp_text).hide.slide_down()
     }
     $.get(url, insert, 'text')
}

my plan is to loop through rown to change the fixed layer, then dumps out the fixed layer :

for ( i=0; i < row_counts ; i++ ){
     staticOverlayDetails(i)
     console.log($(fixed_layer_selector).html())

but the async $.get() call makes this attempt impossible. because only when insert function finished , the content in layer is stable and ready to be dumped, if I use this loop, when $.get returns, the presentation layer is already showing later layers, I don't know how to wait for it.

how can I make my code waiting for the calling back function of $.get() to finish, so I can save the full details for the row, then continue to loop with the next row ?

according to link , I tried to modify the $.get request in the function load_content_for_an_element sync :

function load_description (url, description_selector) {

     function insert ( descrp_text ) {
          $(description_selector).html(descrp_text).hide.slide_down()
     }

     $.get({url:url, success:insert, sync:false});

}

but the browser make request to https://host.address/[object%20Object] and it returns with 404 error. seems it convert the passed object to string, then treat it as url to fetch.

some additional info:

1, because this project has several tables each with different rendering logic, I want to make the changes as small as possible, that's why I want to dump the generated presentation layer instead of changing the generating code itself. all different tables render the same layer, that's the easiest way to do it.

2, I want to dump the code to generate an page to read, only need to dump once , so there is no worries about performance. actually I can use a mouse macro to do it , but I think that's too dumb, I want to learn the javascript way to do it :)

I'm so sorry my English is bad and I want to express such a complex situation, so please ask for more infos if my words are not clear, I'm so sorry to see other people waste time because of my mistake words...

social_loser
  • 143
  • 1
  • 6

1 Answers1

1

Promises are your friend. Here's an example of how you would structure your code to use them:

// Set up a staging area
var staticOverlays = [];
loadStaticOverlayDetails(index) {
  return $.get(url, insert, data....).then(function (data) {
    staticOverlays[index] = data;
  });
}

// Request your data
var promises = [];
for ( var i=0; i < 100; i++ ) {
     promises.push(loadStaticOverlayDetails(i));
}

// Wait for the data to complete loading
$.when(promises).then(function insert() {
  for ( i=0; i < staticOverlays.length; i++ ) {
    var overlay = staticOverlays[i];

    // step 1:generate html text structure for the row, but leaves an element blank
    var txt = html_code_generated

    // insert data into element in fixed layer;
    $(fixed-layer).html(txt);
  }
});

As an aside, if you're really making 100+ http requests you should consider moving some of this logic to the server because that many http requests will hurt your user experience...

Chris Camaratta
  • 2,729
  • 22
  • 35
  • thank you for your answer, I'm so sorry my words are vague and some info in the question are said wrongly. I modified my question a little. don't modify your anwser because it may waste your time because maybe you will be mislead again. I will take time to learn Promise now and to see if I can solve the problem with it. if I can solve the problem with Promise, then you can modify your answer to fit it. – social_loser Apr 08 '18 at 18:07
  • Sure thing; thanks. I still believe promises are the way to go for you, but you will need to think about the problem slightly differently. Using promises will let you run more than one http request at once; this means the data will load faster, but since they're async the order of completion isn't guaranteed. This problem is solved using the `staticOverlays` array to store the responses in their original order. `$.when()` is used to await the completion of all http requests. With these two operations in place all that's left is to loop through the responses and update the page as needed. – Chris Camaratta Apr 08 '18 at 23:21