Non sei sicuro di quanto sia flessibile o di quanti casi hai bisogno per coprire, ma per il tuo esempio, se il testo viene sempre prima dei primi tag HTML, perché non dividere semplicemente l'html interno nel primo tag e prendere il primo:
$('#listItem').html().split('<span')[0];
e se ne hai bisogno più largo, forse solo
$('#listItem').html().split('<')[0];
e se hai bisogno del testo tra due marcatori, come dopo una cosa ma prima di un'altra, puoi fare qualcosa di simile (non testato) e usare le istruzioni if per renderlo abbastanza flessibile da avere un marcatore di inizio o fine o entrambi, evitando errori di riferimento null :
var startMarker = '';// put any starting marker here
var endMarker = '<';// put the end marker here
var myText = String( $('#listItem').html() );
// if the start marker is found, take the string after it
myText = myText.split(startMarker)[1];
// if the end marker is found, take the string before it
myText = myText.split(endMarker)[0];
console.log(myText); // output text between the first occurrence of the markers, assuming both markers exist. If they don't this will throw an error, so some if statements to check params is probably in order...
Generalmente creo funzioni di utilità per cose utili come questa, le faccio libere da errori e quindi faccio affidamento su di esse una volta solide, piuttosto che riscrivere sempre questo tipo di manipolazione di stringhe e rischiare riferimenti null ecc. In questo modo, puoi riutilizzare la funzione in molti progetti e non deve mai perdere altro tempo a eseguire il debug perché un riferimento a stringa ha un errore di riferimento indefinito. Potrebbe non essere il codice a 1 riga più corto di sempre, ma dopo avere la funzione di utilità, è una riga da allora in poi. Nota che la maggior parte del codice sta semplicemente gestendo i parametri presenti o meno per evitare errori :)
Per esempio:
/**
* Get the text between two string markers.
**/
function textBetween(__string,__startMark,__endMark){
var hasText = typeof __string !== 'undefined' && __string.length > 0;
if(!hasText) return __string;
var myText = String( __string );
var hasStartMarker = typeof __startMark !== 'undefined' && __startMark.length > 0 && __string.indexOf(__startMark)>=0;
var hasEndMarker = typeof __endMark !== 'undefined' && __endMark.length > 0 && __string.indexOf(__endMark) > 0;
if( hasStartMarker ) myText = myText.split(__startMark)[1];
if( hasEndMarker ) myText = myText.split(__endMark)[0];
return myText;
}
// now with 1 line from now on, and no jquery needed really, but to use your example:
var textWithNoHTML = textBetween( $('#listItem').html(), '', '<'); // should return text before first child HTML tag if the text is on page (use document ready etc)