繁体   English   中英

用另一个承诺履行(不解决)承诺

[英]Fulfill (don't resolve) promise with another promise

我想兑现一个诺言。 关键是我真的想在第一个诺言兑现后立即访问(仍在等待中)第二个诺言 不幸的是,当两个诺言都实现时,我似乎只能获得第二个诺言的解决值。

这是我要记住的用例:

var picker = pickFile();

picker.then(  // Wait for the user to pick a file.
    function(downloadProgress) {
        // The user picked a file. The file may not be available just yet (e.g.,
        // if it has to be downloaded over the network) but we can already ask
        // the user some more questions while the file is being obtained in the
        // background.

        ...do some more user interaction...

        return downloadProgress;
    }
).then( // Wait for the download (if any) to complete.
    function(file) {
        // Do something with the file.
    }
)

pickFile函数显示文件选择器,用户可以在其中从自己的硬盘驱动器或URL中选择文件。 它返回一个诺言picker ,该picker在用户选择文件后立即完成。 此时,我们可能仍然必须通过网络下载所选文件。 因此,我无法将所选文件作为分辨率值来实现picker 取而代之的是, picker还应满足另一个承诺downloadProgress ,而该承诺最终将与所选文件一起实现。

对于完整性,这是pickFile函数的模拟实现:

function pickFile() {
    ...display the file picker...

    var resolveP1 = null;

    var p1 = new Promise(
        function(resolve, reject) {
            resolveP1 = resolve;
        }
    );

    // Mock code to pretend the user picked a file
    window.setTimeout(function() {
        var p2 = Promise.resolve('thefile');
        resolveP1(p2);  // <--- PROBLEM: I actually want to *fulfill* p1 with p2
    }, 3000);

    return p1;
}

标记行中的问题是我想用新的诺言p2实现诺言p1 ,但是我只知道如何解决它。 满足与解决之间区别在于 ,解决首先检查提供的值p2是否再次是一个承诺。 如果是,则将p1实现推迟到p2满足,然后使用p2的分辨率值而不是p2本身来实现p1

我可以通过围绕p2构建包装器来解决此问题,即替换行

        resolveP1(p2);  // <--- PROBLEM: I actually want to *fulfill* p1 with p2

从第二个代码示例

        resolveP1({promise: p2});

然后,在第一个代码示例中,我将不得不替换该行

        return downloadProgress;

通过

        return downloadProgress.promise;

但是,当我真正想做的只是兑现(而不是解决)承诺时,这似乎有点不合时宜。

我将不胜感激任何建议。

除了我已经在问题中描述的解决方法之外,似乎没有其他解决方案。 供将来参考,如果您想实现(而不是解决)带有值val的promise p ,其中val是另一个promise,那么仅使用参数val调用p的promise解析函数将无法按预期工作。 这将导致p被“锁定”在val的状态上,这样一旦val满足, p将以val的分辨率值实现(请参见spec )。

而是将val包装在另一个对象中,并使用该对象解析p

var resolveP;  // Promise resolution function for p

var p = new Promise(
    function(resolve, reject) {
        resolveP = resolve;
    }
);

function fulfillPwithPromise(val) {  // Fulfills p with a promise val
    resolveP({promise: val});
}

p.then(function(res) {
    // Do something as soon as p is fulfilled...

    return res.promise;
}).then(function(res) {
    // Do something as soon as the second promise is fulfilled...
});

如果您已经知道val是一个承诺,则此解决方案有效。 如果您不能对val的类型做任何假设,那么您似乎不走运。 要么你必须在另一个对象总是包裹承诺分辨率值,或者你可以尝试检测是否val有一个字段then类型的“功能”,并有条件地包裹。

也就是说,在某些情况下,承诺解决方案的默认行为实际上可能会达到预期的效果。 因此,仅当您确定要实现而不是用第二个承诺来解决第一个承诺时,才使用上述解决方法。

尽管不同的人使用不同的术语,但在通用术语中,“实现”是指将承诺置于“成功”状态(与“拒绝”相对),该状态将触发then处理程序将其挂起。

换句话说,您不能用承诺“履行”承诺。 您可以实现自己的价值。 (顺便说一句,“解决”一词通常指实现或拒绝。)

您可以做的是从.then处理程序返回一个诺言,这实际上将用返回的诺言替换原始诺言。

这是一个简单的例子:

asyncTask1 . then(asyncTask2) . then(processData)

其中asyncTask1是一个承诺,而asyncTask2是一个返回一个承诺的函数。 所以,当asyncTask1满足(成功完成),然后asyncTask2运行,并通过返回的承诺.then被“接管”的承诺asyncTask2回报,这样,当它结束时,数据可以被处理。

我可以通过以Promise.resolve作为参数调用Promise.resolve来做类似的事情。 这有点用词不当,因为我没有从技术角度解决诺言。 相反,创建的新承诺被我传入的承诺“占用”。它也没有用,因为使用结果与使用我传入的承诺完全相同:

Promise.resolve(asyncTask2)

行为与

asyncTask2

(假设asyncTask2已经是一个承诺;否则Promise.resolve可以创建一个保证,并立即通过传入的值来实现。)

就像可以将Promise.resolve传递给Promise.resolve ,您也可以将Promise.resolve传递给作为Promise.resolve构造函数回调的参数提供给您的resolve函数。 如果您传递来resolve的参数是非承诺,则promise将立即用该值兑现。 但是,如果传递给您resolve的参数是另一个promise,则该promise将“接管您正在构建的promise的主体”。 换句话说,您正在构造的promise的行为与传递给resolve的promise的行为完全相同。

“精确地表现”是指,如果您传递来resolve的诺言已经兑现,那么您正在构造的诺言将立即以相同的价值兑现。 如果您传递来resolve的承诺已被拒绝,则您出于相同原因立即构造的承诺将被拒绝。 如果您在通过承诺resolve尚未解决,那么任何then处理你挂过你正在构造是否以及何时你通过的承诺将被调用的承诺resolve得到解决。

正如它是混淆的是Promise.resolve可能导致实际上未解决的承诺,它也同样混乱,在调用的resolve交给你作为参数传递给许构造函数实际上可能没有解决的承诺,如果你调用正在建设中它有一个未解决的承诺。 相反,正如我现在已经说过几次,它的作用是使正在构建的承诺与通过resolve的承诺完全一致。

因此,除非我遗漏了您的问题, pickfile可以写为

function pickFile() {
  return new Promise(function(resolve, reject) {
    ...display the file picker...

    // Mock code to pretend the user picked a file
    window.setTimeout(function() {
        resolve('thefile');
    });
}

我不太清楚您的问题,因此可能不是您想要的。 请说明您是否愿意。

在从Angular的$ q转​​到本机Promise功能的过程中找到了类似的解决方案。 Promise.all可能是一个选择(在独立并行异步任务的情况下),方法是传递适当的对象或带有状态修饰的对象,并在适当的时候传递给已准备好的对象。 在下面的Promise.all示例中,请注意它如何在承诺中恢复-让我花了一会儿意识到如何重定向链的结果。 一切的结果只是最后诺言的回报。 尽管这不能回答问题的标题,但使用return Promise.reject(<an-object-including-a-promise>) (或解决)可在执行过程中提供一系列和/或一组异步任务共享访问和控制。 在采摘,下载然后我拿出进度的事件处理则文件工作的情况下,这样做: pickFile.then(download,orFailGracefully)downloadProgress的内部处理download onResolve处理程序(下载进度不会出现是一个异步任务)。 以下是控制台中的相关实验。

var q = {
defer: function _defer(){
    var deferred = { };
    deferred.promise = new Promise(function(resolve, reject){
        deferred.resolve = resolve;
        deferred.reject = reject;
    });
    return deferred;
    }
};

var communityThatCares = q.defer();
communityThatCares.promise.then(function(someGood){
    console.log('someGood', someGood);
    return someGood;
}, function(someBad){
    console.warn('someBad', someBad);
    return someBad;
});

(new Promise(function(resolve, reject){ communityThatCares.about = 'communityThatCares'; setTimeout(resolve,1000, communityThatCares); }))
.then(
function(e){
    console.log(3,e); return e.resolve(e);
}, function(e){
    console.warn(3, e); return e.reject(e);
});

var todo = {
    find:'swan'
};

var greaterGood = [(
(new Promise(function(res,rej){ res(todo); })).then(function(e){ e.stuff = 'things'; return e; }),
(new Promise(function(res,reject){ 
    reject(todo);
})).then(function(e){ return e; }
,function(e){
    console.warn(1,e);
    e.recover = 'uh oh';
    return Promise.resolve(e);
}).then(function(e){ console.log(2,e); return e; }),
(new Promise(function(res,rej){ res(todo); })).then(function(e){ console.log(1,e); e.schedule = 'today'; return e; },function(e){ console.warn(1,e); return e; }).then(function(e){ console.log(2,e); return e; }))
];

var nkay = Promise.all( greaterGood )
.then(function(todo){
    console.log('all',todo[0]); return todo;
}, function(todo){
    console.warn('all',todo[0]); return todo;
});

暂无
暂无

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

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