2016-08-04 11 views
0

Die unten stehende Funktion nimmt eine Reihe von Wörtern ruft eine API für Informationen zu jedem Wort und speichert die Daten in der definitions Objekt. Ich habe ein Versprechen gegeben, auf eine Serverantwort zu warten, bevor ich irgendwelche Daten zurückgebe.Auflösen Funktion in Javascript Versprechen verhält sich nicht konsequent

function define(arr) { //pyramid of doom at the expense of adding abstraction 
     return new Promise(function(resolve, reject) { 
     var client = []; 
     var definitions = {}; 
     for (var i = 0, len = arr.length; i < len; i++) { 
      (function(i) { 
       client[i] = new XMLHttpRequest(); 
       client[i].onreadystatechange = function() { 
        if (client[i].readyState === 4 && client[i].status === 200) { 
        definitions[arr[i]] = JSON.parse(client[i].responseText); 
         if (Object.keys(definitions).length === arr.length) { 
         resolve(definitions); 
         } 
        } 
       }; 
       client[i].open('GET', 'http://api.wordnik.com:80/v4/word.json/' + arr[i] + 
       '/definitions?limit=1&includeRelated=false&sourceDictionaries=all&useCanonical=false&includeTags=false&api_key=737061636520696e74656e74696f6e616c6c7920626c616e6', 
       true); 
       client[i].send(); 
       })(i); 
      } 
     }); 
    } 

Wenn jedes Element mit dem arr Argumente ein Wort in der API-Datenbank Wordnik ist das obige Programm funktioniert gut. Wenn ein Nicht-Wort übergeben wird, bricht das Programm zusammen. Ich möchte es so machen, dass jedes Nicht-Wort entweder weggelassen wird oder "Definition nicht gefunden" anzeigt.

Die Entschlossenheit Funktion einen Klick Eventhandler und wenn ein nicht Wort erzeugt dann zu define geben wird, wenn der Event-Handler wird durch einen Klick, den Fehler ausgelöst hat „Uncaught Typeerror: kann nicht lesen Eigenschaft‚0‘undefinierter“ erscheint für eine Leitung mit dem Code obj[this.id][0].text.

habe ich versucht, auf die onreadystate anonyme Funktion in diesem bedingten Zusatz:

if (client[i].responseText[0] === undefined) { 
    client.responseText[0] = { 
     word: arr[i], 
     text: 'Definition not found' 
    }; 

aber nicht alles reparieren.

Antwort

0

Ihr Zustand ist korrekt, aber der ausgeführte Code ist nicht korrekt. Tun Sie einfach so etwas wie dieses:

if (client[i].responseText[0] === undefined) { 
    reject('Word not found'); 
} 

Dann in Ihrem Code machen den Anruf an define(arr) etwas wie folgt aussieht:

define(arr).catch(function(error) { 
    alert(error); 
}); 

Dieser Code ist nur ein Beispiel, können Sie es für Sie geeignet machen!

1

responseText ist eine Zeichenfolge. Sie sind als JSON Parsen hier:

definitions[arr[i]] = JSON.parse(client[i].responseText); 

Das Problem einer Definition nicht gefunden wird, ist nicht in Ihrem Anforderungscode. Wo auch immer Sie das Ergebnis des Versprechens verwenden, sollten Sie überprüfen, ob das Definitionsfeld leer ist. Der Ort, wo der Fehler auftritt, klingt vielversprechend:

… the error "Uncaught TypeError: Cannot read property '0' of undefined" appears for a line with the code obj[this.id][0].text .

obj[this.id][0].text vor dem Lesen diese obj[this.id].length !== 0 gewährleisten.

var definitions = obj[this.id]; 
var something = 
    definitions.length === 0 ? 
     'Definition not found' : 
     definitions[0].text; 

Auch Sie Neuimplementierung Promise.all durch Tasten zu zählen. Ich würde vorschlagen, eine separate Funktion zu machen, um ein Wort zu definieren.

var API_KEY = '737061636520696e74656e74696f6e616c6c7920626c616e6'; 

function queryString(map) { 
    return '?' + 
     Object.keys(map) 
      .map(function (key) { 
       return key + '=' + encodeURIComponent(map[key]); 
      }) 
      .join('&'); 
} 

function defineWord(word) { 
    return new Promise(function (resolve, reject) { 
     var request = new XMLHttpRequest(); 
     var uri = 
      'http://api.wordnik.com/v4/word.json/' + encodeURIComponent(word) + 
      '/definitions' + queryString({ 
       limit: 1, 
       includeRelated: false, 
       sourceDictionaries: 'all', 
       useCanonical: false, 
       includeTags: false, 
       api_key: API_KEY, 
      }); 

     request.addEventListener('error', reject); 
     request.addEventListener('load', function() { 
      resolve(this.response); 
     }); 

     request.responseType = 'json'; 
     request.open('GET', uri, true); 
     request.send(null); 
    }); 
} 

function define(words) { 
    return Promise.all(words.map(defineWord)) 
     .then(function (results) { 
      var definitions = {}; 

      results.forEach(function (result, i) { 
       definitions[words[i]] = result; 
      }); 

      return definitions; 
     }); 
} 
+0

Dank sind Sie richtig über das Problem, das ich denke, nicht in der Anfrage ist. Aus irgendeinem Grund scheint es, wenn ich ein Nicht-Wort übergebe, dass das Definitionsobjekt irgendwie bricht. Ich denke, ich muss eine neue Frage mit besseren Informationen stellen. – Michael

+0

@Michael: Haben Sie den Wert von 'this.id' und' obj' mit einem Debugger überprüft? – Ryan

+0

Ja this.id funktioniert gut, zeigt die ID des Elements, auf das geklickt wird. Obj zeigt "TypeError: Kann Eigenschaft 'Wort' von undefined (...) nicht lesen" – Michael