繁体   English   中英

什么是 JavaScript“惯用”的从外部解决 promise 的方法?

[英]What is the JavaScript “idiomatic” way of settling a promise externally?

在一个程序中,我发现外部可设置 promise(因为没有更好的词)的概念很有用。 用例是:程序中的多个位置需要某个值,但在一个特定位置(作为其他工作的一部分)异步计算。 所以想法是预先定义一个全局变量来保存一个 promise 的值:

让变量 = settlablePromise();

(其中 settlablePromise 是一个实用程序 function - 见下文)。

无论在哪里需要值,我们都可以简单地.then 或 await 变量(因为它已被分配了一个承诺)。

程序中计算值的地方将调用 variable.settle(x) 其中 x 是计算值。

这个方案有效,但我想知道是否有更标准的方法,而不是下面的“settlablePromise”function。 它的 function 是生产一个可外部设置的 promise:

function settlablePromise()
{
    let resolver = null;
    let p = new Promise( (resolv,err) => {
        resolver  = resolv;
    });
    p.settle = function(v)
    {
        resolver(v);
    };
    return p;
}

该方案有效,但我想知道是否有更标准的方法

很大程度上,答案是:不要。 :-) 相反,这样做:

const variable = xyz();

...并使xyz成为可以完成获取值工作的代码部分,而不是让该代码稍后调用variable.settle(x) 暴露结算方法的问题在于它们可以被任何代码调用,可能不止一次,但只有一个调用会对 promise 产生影响。 因此,该设计有意使这些代码专用于创建 promise 的代码。 如果没有启动一些可以报告完成的异步操作,promise 将毫无意义。

如果将执行异步工作的代码尚未准备好立即开始工作,您仍然可以让xyz返回 promise 并让该代码稍后启动该过程。 结算方法将对该代码保持私有,而不是暴露给所有代码,保持封装。

这是一个罕见的用例,通常您希望在创建 promise 时开始工作。 但在这种罕见的情况下,您可以在不暴露结算功能的情况下做到这一点。

例如:

// In a module specific to the asynchronous work
let [promise, start] = (() => {
    let start;
    const promise = new Promise((resolve, reject) => {
        start = () => {
            // ...Actually start the work, handle completion by calling
            // `resolve` or `reject...
        };
    });
    return [promise, start];
})();
export function xyz() { // The public face of the work
    return promise;
}

// Code elsewhere in the module starts the process via `start`

您甚至可以直接公开 promise 而不是使其成为 function 调用的结果:

// In a module specific to the asynchronous work
let [promiseOfNiftyStuff, start] = (() => {
    let start;
    const promise = new Promise((resolve, reject) => {
        start = () => {
            // ...Actually start the work, handle completion by calling
            // `resolve` or `reject...
        };
    });
    return [promise, start];
})();
export { promiseOfNiftyStuff };

// Code elsewhere in the module starts the process via `start`

同样,这是一个罕见的用例。

Yury Tarabanko提供了一个很好的例子来说明你需要将结算处理程序泄漏到包含上下文的“罕见”用例,并且仍然保持良好的封装(在本例中为fromEvent ):

 async function* fromEvent(element, event) { let resolve = null; element.addEventListener(event, (event) => { resolve(event); }); while (true) { yield new Promise(r => { resolve = r; }) } } async function run() { const button = document.getElementById('test'); for await (const event of fromEvent(button, 'click')) { console.log('clicked'); } } run();
 <button id="test">Click</button>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM