Можно ли разрешить обещание с помощью действия пользователя или триггеров, управляемых вручную? Да, поэтому мы можем создавать редактируемые обещания - PullRequest
1 голос
/ 01 августа 2020

Я хочу, чтобы программа запускала цепочку действий после выполнения определенного действия пользователя. Однако часть цепочки должна будет дождаться разрешения предыдущего обещания ИЛИ того факта, что пользователь выполнил какое-то действие. Можно ли заставить Promise работать таким образом?

Я представляю, что идеальный сценарий программы выглядит так:

var coreTrigger = Promise.any([normalAsyncRequest, userAction]);
coreTrigger.then(res=>{
  // the followup action
});

...

// somewhere far away, or in developer console
userAction.done(); // I want this can be one possible path to trigger the followup action

Ответы [ 2 ]

2 голосов
/ 02 августа 2020

Да!

function createUserAction() {
    let resolve = undefined;
    const promise = new Promise(r => { resolve = r });

    function done() {
        resolve();
    }

    function wait() {
        return promise;
    }

    return { done, wait }
}

И используйте его, как вы описали в своем вопросе.

const userAction = createUserAction();
var coreTrigger = Promise.any([normalAsyncRequest, userAction.wait()]);
coreTrigger.then(res=>{
  // the followup action
});

// Somewhere else
userAction.done();
0 голосов
/ 01 августа 2020
  • Пример 1: разрешить внешнему вызову разрешить Promise.
  • Пример 2: изменение обещания после создания comPromise.
  • Пример 3 и 4: прямое создание comPromise с PromiseList.
async function doAsync(syncMethod, timeout) {
    try {
        if (timeout != null) {
            setTimeout(()=>syncMethod(), timeout)
        } else syncMethod();
    } catch (e) {console.error(e);}
}

class comPromise extends Promise {
    constructor(resolver) {
        var outBox = undefined;
        super((resolve, reject)=>outBox={resolve:resolve, reject:reject});
        this.promiseList = [new Promise(resolver)];
        this.quantifier = 'race';
        this.needReplacement = false;
        this.state = 'pending';
        (async ()=>{
            try {
                while (true) {
                    this.replacer = triggerFactory();
                    var result = await Promise.race([
                        Promise[this.quantifier](this.promiseList),
                        this.replacer.promise
                    ]);
                    if (this.state == 'aborted') {
                        return;
                    } else if (!this.needReplacement) {
                        this.state = 'fulfilled';
                        return outBox.resolve(result);
                    } else {
                        this.needReplacement = false;
                    }
                }
            } catch(e) {return outBox.reject(e);}
        })();
    }
    refreshCondition() {
        this.needReplacement = true;
        this.replacer.fire();
    }
    testQuantifier() {
        console.log(this.quantifier);
        console.log(this.promiseList);
        return Promise[this.quantifier](this.promiseList);
    }
    forceOutcome(action) {
        if (this.state == 'fulfilled') {
            throw Error('Promise is already fulfilled!');
        } else {
            this.needReplacement = false;
            action();
            return this;
        }
    }
    abort() {return this.forceOutcome(()=>{this.state == 'aborted'; this.replacer.fire();});}
    forceResolve(result) {return this.forceOutcome(()=>this.replacer.fire(result));}
    forceReject(error) {return this.forceOutcome(()=>this.replacer.cancel(error));}
    redefine(promiseList, quantifier) {
        this.promiseList = promiseList;
        this.quantifier = quantifier;
        this.refreshCondition();
        return this;
    }
    static composite(promiseList, quantifier) {
        var cp = new comPromise(s=>'never resolve or reject');
        cp.quantifier = quantifier;
        cp.promiseList = promiseList;
        cp.refreshCondition();
        return cp;
    }
    static all(promiseList) {return this.composite(promiseList, 'all');}
    static allSettled(promiseList) {return this.composite(promiseList, 'allSettled');}
    static any(promiseList) {return this.composite(promiseList, 'any');}
    static race(promiseList) {return this.composite(promiseList, 'race');}
}

var trigs = {};
function triggerFactory(name) {
    console.debug('new trigger requested:', name);
    var resolveCall = undefined;
    var rejectCall = undefined;
    var trigger = {
        fired: false,
        fire(result) {
            if (this.fired) {throw Error('Trigger is already fired!');}
            this.fired = true;
            this.result = result;
            resolveCall(result);
        },
        cancel(e) {rejectCall(e);},
        promise: new Promise((s,f) => [resolveCall,rejectCall] = [s,f])
    };
    if (name != null) trigs[name] = trigger;
    return trigger;
}

// Example 1
var manualTrigger = Promise.any([new Promise(()=>'never resolve or reject'), triggerFactory('manual').promise]);
manualTrigger.then(res=>{
    console.log('Core trigger done!', res);
});
trigs['manual'].fire('manualTrigger resolved by manual trigger');

// Example 2
var cpNever = new comPromise(()=>'never resolve or reject');
cpNever.then(x=>console.log(x));
doAsync(()=>{
    cpNever.promiseList.push(new Promise(s=>s('cpNever resolved by this new promise')));
    cpNever.quantifier = 'any';
    cpNever.refreshCondition();
}, 1000);

// Example 3
var allAB = comPromise.all([triggerFactory('A').promise, triggerFactory('B').promise]);
allAB.then(x=>console.log('All A and B fulfilled',x)).catch(e=>console.error(e));
doAsync(()=>{
    trigs['A'].fire('result of A');
    trigs['B'].fire('result of B');
}, 2000);

// Example 4
var anyCD = comPromise.any([triggerFactory('C').promise, triggerFactory('D').promise]);
anyCD.then(x=>console.log('Any of C and D fulfilled',x)).catch(e=>console.error(e));
doAsync(()=>{
    trigs['C'].cancel('cancelling C');
    trigs['D'].fire('result of D');
}, 3000);

EDIT

  • наконец, теперь он работает! Ara sh Motamedi , я отполировал определение фабрики триггеров, чтобы оно выглядело более стабильно
  • после некоторого изучения, дополнительно отполировал класс и добавил basi c force actions
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...