Дождаться выполнения Promise
Интересует на примере кода допущенные ошибки использования Promise. Почему getFiles выполняется раньше auth и как сделать ожидание ответа авторизации и только потом выполнение getFiles?
var StorageCloud = {};
StorageCloud.API = function(parameters) {
this.url = parameters['url'] || null;
this.login = parameters['login'] || null;
this.password = parameters['password'] || null;
this.AuthToken = parameters['AuthToken'] || null;
var ajaxGetAuthToken = async function(url, login, password) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
type: 'POST',
timeout: 30000,
dataType: 'json',
data: {
Module: 'Core',
Method: 'Login',
Parameters: '{"Login": "' + login + '", "Password" : "' + password + '"}'
},
success: (response) => {
resolve(response);
},
error: (response) => {
reject(response);
}
})
})
}
var ajaxGetFiles = async function(url, token) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
type: 'POST',
async: true,
dataType: 'json',
headers: {
'Authorization': 'Bearer ' + token
},
data: {
Module: 'Files',
Method: 'GetFiles',
Parameters: '{"Type" : "personal", "Path": "", "Pattern": ""}'
},
success: (response) => {
resolve(response);
},
error: (response) => {
reject(response);
}
});
})
}
this.getFiles = function(parameters) {
(async () => {
return await ajaxGetFiles(this.url, this.AuthToken);
})();
}
this.auth = function(parameters) {
if (this.AuthToken == null) {
this.onSuccesAuth = parameters['onSuccesAuth'] || function() {};
this.onFailedAuth = parameters['onFailedAuth'] || function() {};
(async () => {
this.response = await ajaxGetAuthToken(this.url, this.login, this.password);
if (this.response.hasOwnProperty('ErrorCode')) {
this.onFailedAuth();
} else {
this.AuthToken = this.response.Result.AuthToken;
this.onSuccesAuth();
}
})();
}
}
};
var StorageCloud = new StorageCloud.API({
url: "http://file/index.php?/Api/",
login: "root",
password: "root"
});
StorageCloud.auth({
onSuccesAuth: function() {
console.log(this.AuthToken);
},
onFailedAuth: function() {
console.log(this.response.ErrorCode);
}
});
console.log(StorageCloud.getFiles());
Ответы (2 шт):
Уберите слова async из описаний функций ajaxGetAuthToken и ajaxGetFiles, возвращаемые промисы уже асинхронные.
И вот этот код уберите:
this.getFiles = function(parameters) {
(async () => {
return await ajaxGetFiles(this.url, this.AuthToken);
})();
}
Он лишний, вызывайте сразу ajaxGetFiles.
Вообще, ваш код очень странный. Вы хотите соединить сразу четыре подхода: подход с асинхронные функциями, подход с промисами и callback-driven-подход и как соус к этому венегрету добавили ООП-парадигмы.
Ваш класс должен был быть построен приблизительно так:
class API {
static get defaults(){
return {
url: '',
login:'',
password:''
}
}
constructor(params){
Object.assign(this, API.defaults, params);
}
doAuth(){
return $.ajax({
url: url,
type: 'POST',
timeout: 30000,
dataType: 'json',
data: JSON.stringify({
Module: 'Core',
Method: 'Login',
Parameters: JSON.stringify({
Login: this.login,
Password: this.password
})
}),
success: (response) => {
if(response.responseText == 'OK'){
resolve(response);
}
else {
reject('Wrong Login or Password');
}
},
error: (response) => {
reject(response);
}
});
}
getFiles(){
return $.ajax({
url: url,
type: 'POST',
timeout: 30000,
dataType: 'json',
headers: {
Authorization: 'Bearer ' + token
},
data: JSON.stringify({
Module: 'Files',
Method: 'GetFiles',
Parameters: JSON.stringify({
Type: "personal",
Path: "",
Pattern: ""
})
}),
success: (response) => {
resolve(response.responseText);
},
error: (response) => {
reject(response);
}
});
}
}
Всё.
А пользоваться этим классом можно так:
(async () => {
const api = new API({url: '', login:''});
const files;
try {
await api.doAuth();
files = await api.getFiles();
} catch(e){
console.error(e);
} finally {
console.log(files);
}
})();
И вроде понятно всё и лаконично. А у вас как?
PS. В коде могут быть опечатки.
jQuery.ajax реализует интерфейс thenable, поэтому всё проще:
async function auth() {
return await $.ajax('https://httpbin.org/get?auth');
}
/*
Что, с точки зрения вызывающего кода, идентично следующему:
function auth() {
return $.ajax('https://httpbin.org/get?auth');
}
*/
async function getFiles() {
const files = await $.ajax('https://httpbin.org/get?getFiles&a=1&a=2');
return files.args.a;
}
auth()
.then(getFiles)
.then(files => console.log(files))
Асинхронная функция - это функция, которая возвращает Promise.
Можно работать с ним через await в другой асинхронной функции или напрямую, через then.
Важно одно - не нужно терять этот Promise, верните его в вызывающую функцию. Когда вы пишете что-то вроде:
(async () => {
const a = await ...;
...
}())
вы порождаете Promise, который нигде не используете. Сохраните его, или верните:
return (async () => {
const a = await ...;
...
}())
Разумеется, сегодня $.ajax не нужен, в современных браузерах есть FetchApi