ES6 async/await dans les classes
Je suis en train de créer une classe qui va envoyer une requête post (login), enregistrer le cookie et l'utilisation de ce cookie pour d'autres opérations telles que le téléchargement d'un fichier.
J'ai créé un serveur local qui recevra une méthode http post avec d'utilisateur et le mot de passe et un routeur appelé /download
qui ne seront accessibles que si l'utilisateur est connecté, sinon il sera de retour you need to log in
.
Le problème:
C'est le prototype de ma classe (avant de la main):
const request = require('request-promise-native')
class ImageDownloader {
constructor(username = null, password = null) {
this.username = username
this.password = password
this.cookie = request.jar()
this.init()
}
init() {
//login and get the cookie
}
download() {
//needs the cookie
}
query() {
//needs the cookie
}
}
Comme vous pouvez le voir dans le code ci-dessus j'ai besoin de le cookie pour deux opérations qui est download
et query
j'ai donc bien sur la création d'un init
méthode qui vous permettra d'effectuer les opérations initiales telles que la connexion et l'appeler à droite dans le constructeur de sorte qu'il sera initialisé et mis le cookie sur la variable this.cookie
à utiliser partout, mais ça ne fonctionne pas, il semble que init
est appelé après que toutes les autres méthodes.
const request = require('request-promise-native')
class ImageDownloader {
constructor(username = null, password = null) {
this.username = username
this.password = password
this.cookie = request.jar()
this.init()
}
async init() {
await request({
uri: 'http://localhost/login',
jar: this.cookie,
method: 'post',
formData: {
'username': 'admin',
'password': 'admin'
}
}).catch(e => console.error(e))
}
async download() {
await request({
uri: 'http://localhost/download/image.jpg',
jar: this.cookie
})
.then(b => console.log(b))
.catch(e => console.error(e))
}
query() {
//...
}
}
const downloader = new ImageDownloader
downloader.download()
C'est en revenant à moi que j'ai besoin de vous connecter (réponse du serveur)... MAIS ça marche si je fais ce changement:
async download() {
await init() //<<<<<<<<<<<<
await request({
uri: 'http://localhost/download/image.jpg',
jar: this.cookie
})
.then(b => console.log(b))
.catch(e => console.error(e))
}
Il ne fonctionne que si je l'appelle init
dans le download
méthode.
Si j'ai mis console.log(this.cookie)
dans download
elle renvoie un vide CookieJar
et si je mets le même dans init
il sera de retour le droit cookie, mais il semble APRÈS l'exécution de télécharger même quand je l'ai appelé sur le constructeur avant d'appeler download
.
Comment résoudre ce problème? Je vous remercie beaucoup.
@edit
J'ai fait les modifications que @agm1984 et @Jaromanda X m'as dit mais ça ne fonctionne toujours pas 🙁
const request = require('request-promise-native')
class ImageDownloader {
constructor(username = null, password = null) {
this.username = username
this.password = password
this.cookie = request.jar()
this.init().catch(e => console.error(e))
}
async init() {
return await request({
uri: 'http://localhost/login',
jar: this.cookie,
method: 'post',
formData: {
'username': 'admin',
'password': 'admin'
}
})
}
async download() {
return await request({
uri: 'http://localhost/download/image.jpg',
jar: this.cookie
})
}
query() {
//...
}
}
const downloader = new ImageDownloader
downloader.download()
.then(b => console.log(b))
.catch(e => console.error(e))
Mais là encore... il ne fonctionne pas à moins que j'appelle init
à l'intérieur de download
.
- Je ne comprends pas pourquoi je voudrais retourner tout ce que les opérations à l'intérieur
init
etdownload
n'a pas besoin d'être partagé n'importe où et lerequest-promise-native
va mettre le pot dans lathis.cookie
pour moi (ce dont j'ai besoin), mais le truc, c'est l'ordre des choses sont en cours d'exécution. L'ajout deawait init()
dansdownload
est de se comporter comme "je dois attendre pourinit
à la fin et puis continuer" (quelque chose comme ça), mais comme je l'ai appeléthis.init
dans le constructeur, je pensais qu'il ne serait pas nécessaire. - Désolé, ouais, j'ai mal lu ton code
- comme je l'ai dit, j'ai mal lu ton code, ignorer les modifications que j'ai apportées :p - la plupart d'entre eux ne sont pas requis que j'ai foiré mon la connaissance de async/await :p
- C'est bien, vous avez essayé de l'aider et je comprends parfaitement ce que tu veux dire. Merci à vous de toute façon.
- le problème est maintenant que
download
l'habitude d'attendreinit
- dans le constructeur, essayez d'ajouter
this.initp = this.init();
... puis dansdownload
ajouterawait this.initp;
la première ligne - Exactement, je ne veux pas être l'appel de
init
dans chaque méthode unique j'ai besoin de le cookie, donc de façon logique, j'ai pensé: ce sujet j'ai créé une méthode qui est appelée une fois dans le constructeur et utilisé par la suite partout, eh bien, en théorie, il fonctionne comme un charme, mais dans la pratique, nah. Je pensais que leawait
ferait l'affaire et attendre jusqu'à ce qu'elle se termine, et comme je suis d'appelerdownload
à l'aide de la méthode concrète deImageDownloader
j'ai aussi bien que qui il ferait appeldownload
aprèsinit
de toute façon. - Il ne fonctionne pas mais ça va faire des demandes de connexion, encore et encore chaque fois que j'appelle
download
ou l'utilisation d'une autre méthode, c'est la même chose pour appeler:await this.init()
àawait this.initp
- pas si vous faites ce que je suggère ... ajouter
this.initp = this.init();
àconstructor
(s'exécute une fois), puis ajouterawait this.initp;
comme la première ligne dedownload
mais vous aurez également besoin dereturn await request({
dansdownload
(comme vous le faites MAINTENANT) si vous souhaitez vous rendre à l'résolu de données - Oui, vous avez raison, il fonctionne, le seul truc c'est que je ne suis pas à l'aise encore et n'est heureux qu'il n'y a pas d'autre moyen de le faire sans avoir besoin d'appeler
await this.initp
dans chaque méthode qui doit le cookie, il ressemble tellement à spaghetti. 🙁 - Je voudrais séparer les préoccupations et injecter le cookie dans l'image downloader pour que votre code devient de plus en plus comme:
const cookie = await getCookie(username, password); const image = await (new ImageDownloader(cookie)).download();
- Il y a 2 façons. Soit vous en avez besoin pour maintenir une session (demande de session) ou vous avez besoin de conserver les cookies que @k0pernikus suggéré.
Vous devez vous connecter pour publier un commentaire.
Le problème ici est que
init
est asynchrone. L'utiliser comme ceci:La
download
la fonction est exécutée alors queinit
n'a toujours pas fini encore.Je ne dirais pas la méthode d'initialisation dans le constructeur. Ce que je voudrais faire est de quelque chose comme ceci:
1 - enlever le init appel du constructeur.
2 - utiliser la classe comme ceci:
et si vous appelez init dans un
async
fonction que vous pouvez faire: