【问题标题】:JS Promise Undefined BehaviorJS 承诺未定义的行为
【发布时间】:2017-01-09 18:20:29
【问题描述】:

问题:需要取消承诺

是否可以在执行过程中取消忽略一个promise并在运行时将其替换为另一个promise,以便仅解决其当前状态?

在生产中,我使用 angular $timeout,它定义了一个 cancel() 方法。我模仿它在节点中运行:

//Mimic AngularJS's $timeout
function MyTimeout(delay) {
    var t = null;
    var p = new Promise(function (resolve) {
        t = setTimeout(resolve, delay);
    });
    p.realtimeout = t;
    return p;
}
MyTimeout.cancel = function (myto) {
    clearTimeout(myto.realtimeout);
    /*
     * there is no way to appropriately cancel an existing Promise
     * the best I can do in try and change the state of myto to a rejected
     * Promise. Which doesn't help here since it doesn't truly cancel the last
     * Promise...
     */
    myto = Promise.reject("some reason");
};


var x = null;

function changeState() {
    var delay;

    if (x === null) {
        delay = 1000;
    } else {
        MyTimeout.cancel(x);
        delay = 3000;
    }

    x = MyTimeout(delay).then(print_delay);

    function print_delay() {
        console.log("EXECUTED: %s", delay);
    }
}


changeState();

x.then(function () {
    console.log("DONE");
}).catch(console.error);

changeState();

NodeJS 输出

(node:12461) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): some reason
(node:12461) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

EXECUTED: 1000
DONE
EXECUTED: 3000

预期结果EXECUTED: 3000 应该打印一次。由于设置了标志并且相应地设置了xx 应该指向那个执行上下文。

【问题讨论】:

  • 您能否提供更多关于您希望完成的任务的背景信息?这可能有助于我们了解解决此问题的最佳方法。
  • 一个承诺被解决一次。也许我错了,但您可以使用两个 Promise 并使用 Promise.race 来收听第一个已解决的 Promise。你还需要一些逻辑来拒绝第一个承诺。
  • ".then() 被调用了两次。" 不应该。 .then 只附加一个承诺。创建一个新的 Promise 并将其分配给 mypromise 并不会神奇地移动前一个 Promise 的所有回调。在你打电话给strangeFunc() 之后,你有一个未处理的承诺。
  • 不,mypromise 已被使用后,您无法将其换出,但您可以更改解决方式。
  • @Bergi 为什么不呢?它只是一个变量。

标签: javascript ecmascript-6 angular-promise es6-promise


【解决方案1】:

mypromisex 已被使用后,您不能将其换出,因为更改变量引用根本不会影响第一个 Promise 及其处理程序。您需要影响您已经拥有的承诺的解决过程,为此您需要以某种方式创建它,以便之后您可以更改何时/如何调用resolve

function variableDelay(x) {
    var timer = 0;
    var end;
    return {
        promise: new Promise(resolve => {
            end = () => {
                timer = -1;
                resolve(x);
            };
        }),
        setDelay(d) {
            if (timer < 0) throw new Error("too late");
            if (timer > 0) clearTimeout(timer);
            timer = setTimeout(end, d);
            return this;
        }
    };
}


const {promise:x, setDelay:changeState} = variableDelay();
changeState(1000);
x.then(() => {
    console.log("DONE");
}).catch(console.error);
changeState(3000);

【讨论】:

  • 第一个 Promise 仍然执行 resolve 函数,有没有办法仅在上下文更改后才推迟执行?还缺少)new Promise
  • 不,promise 不会执行任何操作,它是 setDelay 调度 end(与 resolve)。
  • 一个基本的调度器,它会在我们准备好时解决这个承诺......明白了
猜你喜欢
  • 2018-10-11
  • 1970-01-01
  • 1970-01-01
  • 2017-10-06
  • 2015-11-19
  • 2017-01-19
  • 2016-12-10
  • 2015-09-27
  • 1970-01-01
相关资源
最近更新 更多