2015-07-16 1 views
4

J'ai lu tous les articles imaginables sur les promesses de JS, et je n'arrive toujours pas à les comprendre. J'essaie d'utiliser des promesses pour gérer plusieurs XMLHTTPRequests. Par exemple: Lorsque xhr demande 1 & 2, appelez cette fonction.Comment enchaîner les promesses Javascript natives?

code Exemple:

function initSession(){ 
    loadRates(0); 
    loadRates(10); 
    buildTable(); 
    // Get all rates from API, save to localStorage, then build the table. 
} 


function loadRates(days) { 
    var xhr = new XMLHttpRequest(); 
    xhr.onload = function() { 
    // save response to localStorage, using a custom variable 
    localStorage.setItem("rates" + days, xhr.responseText); 
    }; 
    xhr.open('GET', url); 
    xhr.send(); 
} 

function buildTable() { 
    // get data from localStorage 
    // write to HTML table 
} 

Dans ce cas, comment pourrais-je envelopper chaque appel de fonction dans un objet Promise afin que je puisse contrôler quand ils sont appelés?

+1

Peut-être [Comment puis-je promisify XHR native?] (Http://stackoverflow.com/q/30008114/1048572) aide – Bergi

Répondre

2

Avec les rappels, vous répondez toujours via une fonction. Par exemple:

function getUsers (age, done) { 
    // done has two parameters: err and result 
    return User.find({age}, done) 
} 

Promises vous permet de répondre en fonction de l'état actuel:

function getUsers (age) { 
    return new Promise((resolve, reject) => { 
     User.find({ age }, function (err, users) { 
      return err ? reject(err) : resolve(users) 
     }) 
    }) 
} 

Cette aplatit la "pyramide de rappel." Au lieu de

getUsers(18, function (err, users) { 
    if (err) { 
     // handle error 
    } else { 
     // users available 
    } 
}) 

Vous pouvez utiliser:

getUsers(18).then((users) => { 
    // `getPetsFromUserIds` returns a promise 
    return getPetsFromUserIds(users.map(user => user._id)) 
}).then((pets) => { 
    // pets here 
}).catch((err) => { 
    console.log(err) // handle error 
}) 

Donc, pour répondre à votre question, tout d'abord vous voudriez utiliser une promesse pour vos requêtes http:

function GET (url) { 
    return new Promise((resolve, reject) => { 
     let xhr = new XMLHttpRequest() 

     xhr.open('GET', url, true) 
     xhr.onload = function() { 
      if (this.status >= 200 && this.status < 300) { 
       return resolve(xhr.response) 
      } else { 
       return reject({ status: this.status, text: xhr.statusText }) 
      } 
     } 
     xhr.onerror = reject 
     xhr.send() 
    }) 
} 

Ensuite, vous voudriez incorporer ceci dans votre fonction loadRates:

function loadRates (days) { 
    var URL = URL_GENERATOR(days) 
    return GET(URL).catch((err) => { 
     // handle our error first 
     console.log(err) 
     // decide how you want to handle a lack of data 
     return null 
    }).then((res) => { 
     localStorage.setItem('rates' + days, res) 
     return res 
    }) 
} 

Puis, en initSession:

function initSession() { 
    Promise.all([ loadRates(0), loadRates(10) ]).then((results) => { 
     // perhaps you don't want to store in local storage, 
     // since you'll have access to the results right here 
     let [ zero, ten ] = results 
     return buildTable() 
    }) 
} 
+0

Cette première phrase ... Frisson . Imo, vous devriez penser à des promesses comme des * valeurs de retour * (qui portent une charge utile asynchrone). – Bergi

+0

@Bergi Je suppose que les promesses sont des opérations asynchrones qui ne tiennent pas compte de la façon dont elles sont utilisées (c'est pourquoi elles sont généralement plus agréables à utiliser que les rappels) ...? – royhowie

+0

Je pense qu'il est très important de voir que le * représentent * le * résultat * d'une opération (asynchrone) - ni l'opération elle-même, ni les [rappels] seulement (http://stackoverflow.com/a/22562045/1048572) :-) – Bergi

1

De plus, sachez qu'il ya fonction pratique pour faire une demande AJAX et obtenir la promesse - window.fetch. Chrome et Firefox le supporte déjà, pour les autres navigateurs, il peut être polyfilled.

Ensuite, vous pouvez résoudre votre problème avec la facilité

function loadRates(days) { 
    return window.fetch(url).then(function(response) { 
     return response.json(); // needed to parse raw response data 
    }).then(function(response) { 
     localStorage.setItem("rates" + days, response); 
     return response; // this return is mandatory, otherwise further `then` calls will get undefined as argument 
    }); 
} 

Promise.all([ 
    loadRates(0), 
    loadRates(1) 
]).then(function(rates) { 
    return buildTable(rates) 
})