import { BnumPromise } from './BnumPromise.js';
import { isAsync } from './mel.js';
import { BnumEvent } from './mel_events.js';
export { Mel_Promise, Mel_Ajax, WaitSomething };
/**
* @callback MelPromiseCallback
* @param {Mel_Promise} current_promise
* @param {...any} Arguments
* @returns {* | Promise<*>}
*/
/**
* @callback WaitCallback
* @returns {boolean} Si vrai, la boucle s'arrête.
*/
/**
* @callback WaitCallbackAsync
* @returns {Promise<boolean>} Si vrai, la boucle s'arrête.
* @async
*/
/**
* Ajoute des fonctionnalités aux promesses déjà existantes.
* Pour que les fonctions asynchrones soient complètement compatible, le premier argument doit être la promesse elle même.
* Ca sera utile pour arrêter la fonction si la fonction 'Abort' est appelé.
* @template T
* @deprecated Utilisez plutôt {@link BnumPromise}
*/
class Mel_Promise {
/**
*
* @param {(current_promise: Mel_Promise<T>, ...args: any[]) => T | Promise<T> | Mel_Promise<T>} callback Fonction qui sera appelé
* @param {...any} args Arguments de la fonction
*/
constructor(callback, ...args) {
let current;
if (callback.then) current = new BnumPromise(async () => await callback);
else if (isAsync(callback))
current = new BnumPromise(
async (manager, ...argsEx) => {
return await callback(this, ...[...argsEx, manager]);
},
...args,
);
else
current = new BnumPromise(
(manager, ...argsEx) => {
return callback(this, ...[...argsEx, manager]);
},
...args,
);
/**
* Récupère sous forme de BnumPromise
* @returns {BnumPromise<T>}
*/
this.toBnumPromise = () => current;
/**
* Vrai si la fonction est en cours d'éxécution
* @returns {boolean}
*/
this.isPending = () => current.isPending();
/**
* Vrai si la fonction est résolue
* @returns {boolean}
*/
this.isResolved = () => current.isResolved();
/**
* Vrai si la fonction à une erreur
* @returns {boolean}
*/
this.isRejected = () => current.isRejected();
/**
* Vrai si la fonction est stoppée
* @returns {boolean}
*/
this.isCancelled = () => current.isCancelled();
/**
* Fonction appelée lorsque l'on stope la fonction.
*/
this.onAbort = new BnumEvent();
current.onAbort.push((...a) => this.onAbort.call(...a));
/**
* Arrête la fonction
* @returns {Mel_Promise}
*/
this.abort = function () {
return new Mel_Promise(async () => await current.abort());
};
this.create_promise = ({ callback, onAbort = () => {} }, ...args) => {
return new Mel_Promise(
async () => await current.createPromise({ callback, onAbort }, ...args),
);
};
this.create_ajax_request = ({
type,
url,
success,
failed,
onAbort = () => {},
datas = null,
}) => {
return new Mel_Promise(
async () =>
await current.createAjaxRequest(url, {
type,
success,
failed,
onAbort,
data: datas,
}),
);
};
this.create_ajax_post_request = ({
url,
success,
failed,
onAbort = () => {},
datas = null,
}) => {
return this.create_ajax_request({
type: 'POST',
url,
success,
failed,
onAbort,
datas,
});
};
this.create_ajax_get_request = ({
url,
success,
failed,
onAbort = () => {},
}) => {
return this.create_ajax_request({
type: 'GET',
url,
success,
failed,
onAbort,
});
};
this.await_all_childs = () => {
return new Mel_Promise(async () => await current.awaitAllChilds());
};
this.all_child_generator = function* all_child_generator() {
yield* current.allChildGenerator();
};
this.start_resolving = () => {
current.setSignal(BnumPromise.PromiseStates.pending);
};
this.resolve = (why) => {
current.setSignal(BnumPromise.PromiseStates.resolved, why);
};
this.reject = (why) => {
current.setSignal(BnumPromise.PromiseStates.rejected, why);
};
current.start();
//Async functions
this.executor = async () => {
return await current;
};
this.then = function () {
const promise = this.executor();
const value = promise.then.apply(promise, arguments);
return new Mel_Promise(() => value);
};
this.catch = function () {
const promise = this.executor();
return promise.catch.apply(promise, arguments);
};
this.success = (call) => this.then(call);
this.fail = (call) => this.then(() => {}, call);
this.always = (call) => this.then(call, call);
}
*[Symbol.iterator]() {
yield this;
yield* this.all_child_generator();
}
/**
*
* @param {WaitCallback} whatIWait
* @param {number} timeout second
* @returns {WaitSomething}
* @deprecated Utilisez plutôt {@link BnumPromise.Wait}
*/
static wait(whatIWait, timeout = 5) {
return new WaitSomething(whatIWait, timeout);
}
/**
*
* @param {WaitCallbackAsync} whatIWait
* @param {number} [timeout=5]
* @returns {WaitSomethingAsync}
* @deprecated Utilisez plutôt {@link BnumPromise.Wait}
*/
static wait_async(whatIWait, timeout = 5) {
return new WaitSomethingAsync(whatIWait, timeout);
}
/**
*
* @param {number} ms
* @returns {Mel_Promise<void>}
* @deprecated Utilisez plutôt {@link BnumPromise.Sleep}
*/
static Sleep(ms) {
return new Mel_Promise((current) => {
current.start_resolving();
setTimeout(() => {
current.resolve();
}, ms);
});
}
/**
*
* @returns {Mel_Promise}
* @deprecated Utilisez plutôt {@link BnumPromise.Resolved}
*/
static Resolved() {
return new Mel_Promise(() => {});
}
}
/**
* @deprecated Utilisez plutôt {@link BnumPromise.Ajax}
*/
class Mel_Ajax extends Mel_Promise {
constructor({ type, url, success, failed, datas = null }) {
super(
async () =>
await BnumPromise.Ajax.Call(url, {
type,
success,
failed,
data: datas,
}),
);
}
}
/**
* @deprecated Utilisez plutôt {@link BnumPromise.Wait}
*/
class WaitSomething extends Mel_Promise {
/**
*
* @param {WaitCallback} whatIWait
* @param {number} timeout en secondes
*/
constructor(whatIWait, timeout = 5) {
let promise = new Mel_Promise((current) => {
current.start_resolving();
new Mel_Promise(async () => {
let data = null;
let it = 0;
while (!whatIWait() && it < timeout * 100) {
if (current.isCancelled()) {
return {
resolved: false,
msg: 'aborted',
};
}
await Mel_Promise.Sleep(100);
++it;
}
it = null;
if (it >= timeout * 100)
data = {
resolved: false,
msg: `timeout : ${timeout * 10}ms`,
};
else data = { resolved: true };
return data;
}).always((data) => {
current.resolve(data);
});
});
super(promise);
}
}
/**
* @class
* @classdesc Attend une fonction asynchrone
* @extends Mel_Promise
* @package
* @deprecated Utilisez plutôt {@link BnumPromise.Wait}
*/
class WaitSomethingAsync extends Mel_Promise {
/**
*
* @param {WaitCallbackAsync} whatIWait
* @param {number} timeout en secondes
*/
constructor(whatIWait, timeout = 5) {
let promise = new Mel_Promise(async (current) => {
let state = false;
for (let it = 0; it < timeout * 10; ++it) {
state = await current.create_promise({
/**
*
* @param {Mel_Promise} self
*/
callback: (self) => {
self.start_resolving();
setTimeout(async () => {
if (self.isCancelled()) self.reject('aborted');
else self.resolve(await whatIWait());
}, 100);
},
});
if (current.isCancelled()) throw new Error('cancelled');
if (state) break;
}
if (state) return { resolved: true };
else
return {
resolved: false,
msg: `timeout : ${timeout * 10}ms`,
};
});
super(promise);
}
}