web-dev-qa-db-fra.com

Comment forcer JavaScript à copier en profondeur une chaîne?

J'ai du code javascript qui ressemble à ceci:

var myClass = {
  ids: {}
  myFunc: function(huge_string) {
     var id = huge_string.substr(0,2);
     ids[id] = true;
  }
}

Plus tard, la fonction est appelée avec des chaînes de grande taille (100 Mo +). Je veux seulement sauvegarder un identifiant court que je trouve dans chaque chaîne. Toutefois, la fonction de sous-chaîne de Google Chrome (en fait, l'expression régulière dans mon code) ne renvoie qu'un objet "chaîne en tranches", qui référence l'original. Ainsi, après une série d'appels à myFunc, mon onglet chrome manque de mémoire, car les objets temporaires huge_string ne peuvent pas être récupérés.

Comment puis-je faire une copie de la chaîne id de sorte qu'une référence au huge_string ne soit pas conservée et que le huge_string puisse être récupéré?

 enter image description here

36
AffluentOwl

La mise en œuvre de ECMAScript par JavaScript peut varier d’un navigateur à l’autre. Toutefois, pour Chrome, de nombreuses opérations sur les chaînes (substr, slice, regex, etc.) conservent simplement les références à la chaîne originale au lieu de les copier. Il s'agit d'un problème connu dans Chrome ( Bug # 2869 ). Pour forcer une copie de la chaîne, le code suivant fonctionne:

var string_copy = (' ' + original_string).slice(1);

Ce code fonctionne en ajoutant un espace au début de la chaîne. Cette concaténation donne une copie de chaîne dans l'implémentation de Chrome. Ensuite, la sous-chaîne après l'espace peut être référencée.

Ce problème avec la solution a été recréé ici: http://jsfiddle.net/ouvv4kbs/1/

AVERTISSEMENT: le chargement prend beaucoup de temps, ouvrez la console de débogage de Chrome pour voir une impression de progression.

// We would expect this program to use ~1 MB of memory, however taking
// a Heap Snapshot will show that this program uses ~100 MB of memory.
// If the processed data size is increased to ~1 GB, the Chrome tab
// will crash due to running out of memory.

function randomString(length) {
  var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  var result = '';
  for (var i = 0; i < length; i++) {
    result +=
        alphabet[Math.round(Math.random() * (alphabet.length - 1))];
  }
  return result;
};

var substrings = [];
var extractSubstring = function(huge_string) {
  var substring = huge_string.substr(0, 100 * 1000 /* 100 KB */);
  // Uncommenting this line will force a copy of the string and allow
  // the unused memory to be garbage collected
  // substring = (' ' + substring).slice(1);
  substrings.Push(substring);
};

// Process 100 MB of data, but only keep 1 MB.
for (var i =  0; i < 10; i++) {
  console.log(10 * (i + 1) + 'MB processed');
  var huge_string = randomString(10 * 1000 * 1000 /* 10 MB */);
  extractSubstring(huge_string);
}

// Do something which will keep a reference to substrings around and
// prevent it from being garbage collected.
setInterval(function() {
  var i = Math.round(Math.random() * (substrings.length - 1));
  document.body.innerHTML = substrings[i].substr(0, 10);
}, 2000);

 enter image description here

38
AffluentOwl

J'utilise la méthode Object.assign () pour chaîne, objet, tableau, etc.:

const newStr = Object.assign("", myStr);
const newObj = Object.assign({}, myObj);
const newArr = Object.assign([], myArr);

Notez que Object.assign copie uniquement les clés et leurs valeurs de propriétés à l'intérieur d'un objet (un seul niveau). Pour le clonage en profondeur d'un objet imbriqué, reportez-vous à l'exemple suivant:

let obj100 = { a:0, b:{ c:0 } };
let obj200 = JSON.parse(JSON.stringify(obj100));
obj100.a = 99; obj100.b.c = 99; // No effect on obj200
4
Daniel C. Deng

Je devenais un problème en poussant dans un tableau. Chaque entrée se retrouverait dans la même chaîne, car elle référençait une valeur sur un objet qui changeait au fur et à mesure de l'itération des résultats via une fonction .next (). Voici ce qui m'a permis de copier la chaîne et d'obtenir des valeurs uniques dans les résultats de mon tableau:

while (results.next()) {
  var locationName = String(results.name);
  myArray.Push(locationName);
}
0
Kyle s