execute code after all dynamic number GM_xmlhttpRequest are done.

i need it for a script that re-requests CSS files on every webpage, replaces things in them, and puts them in the site as script tags. (with "disabled" property thing and script tags also considered)
for this, i need the script to handle dynamic number of requests, even for different domains, and put the CSS back on the page in correct order. so simply adding them to the page on "onload" doesnt work, since their order would depend on time of loading.

and it was already done and working... until i learned that $.get requests dont work for outside domains.
it was:
for (i = 0; i < document.styleSheets.length; i++) {
if(document.styleSheets[i].href.length > 0 && document.styleSheets[i].disabled != true) {
requests[i] = $.get(document.styleSheets[i].href);
}
}
etc. and then:
$.when.apply(null,requests).then(function(){

$.each(arguments, function(i,row){
  var status = row[1], response = row[0];
  if(status === 'success'){
*response into array and other things*

and after changing the $.get to GM_xmlhttpRequest everything stopped working. not just the $.each, but it also doesnt only execute after the requests are done.
im not sure how to do that, or even how to access the response after it. would i need "promises" or whats, even if it would only execute after the requests are surely done?
and i tried searching for this everywhere, but without finding anything specifically solving this kind of thing, so that is why i would like to ask for help here

Viestejä yhteensä

  • The modern approach is to use await inside a function declared as async:

    (async () => {
      const getUrl = async url => (await fetch(url)).text();
      const hrefs = [...document.styleSheets].filter(s => s.href && !s.disabled).map(s => s.href);
      const responses = await Promise.all(hrefs.map(getUrl));
      console.log(responses);
    })();
    
  • thank you, but is there no oldschooler way? because the script would be for something like a CSS polyfill

  • Do you mean it's for ancient browsers that don't support async/await?
  • well, kindof. i would want it to work on as many browsers and versions as possible.
    since GM_xmlhttpRequest existed way before those, there had to be a way to do it, right? to just wait for the requests to finish and then access the responses? and it already worked with the jquery i posted, so how different is the GM request?

  • GM_xmlhttpRequest doesn't return a Promise, unlike $.get so you need to write a wrapper:

    function gmGet(url) {
      return new Promise(function (resolve, reject) {
        GM_xmlhttpRequest({
          method: 'GET',
          url: url,
          onload: function(e) { resolve(e.responseText) },
          onerror: function(e) { resolve('') },
        });
      });
    }
    

    And use it

    Promise.all(hrefs.map(gmGet)).then(function (texts) {
      console.log(hrefs, texts);
    });
    
  • editoi April 29 [?]

    thank you, it works! at first i didnt realize 'texts' was an array, but now its perfect.
    i also included a Promise polyfill to make it work even more.
    thank you for saving me again ;3

  • @wOxxOm said:
    GM_xmlhttpRequest doesn't return a Promise, unlike $.get so you need to write a wrapper:

    function gmGet(url) {
      return new Promise(function (resolve, reject) {
        GM_xmlhttpRequest({
          method: 'GET',
          url: url,
          onload: function(e) { resolve(e.responseText) },
          onerror: function(e) { resolve('') },
        });
      });
    }
    

    And use it : happy wheels

    Promise.all(hrefs.map(gmGet)).then(function (texts) {
      console.log(hrefs, texts);
    });
    

    Do you mean it's for ancient browsers that don't support async/await?

  • @Marnie Lafferty I meant exactly what I said, there's nothing that needs clarification. As for async/await, it's just a nice syntactic sugar that still needs a Promise wrapper to convert the callback-based GM_xmlhttpRequest.

Kirjaudu sisään tai Rekisteröidy kommentoidaksesi.