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

rob*_*ler 7 javascript ecmascript-6 es6-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.
    }
)
Run Code Online (Sandbox Code Playgroud)

该函数pickFile显示文件选择器,用户可以从自己的硬盘驱动器或URL中选择文件.它返回一个picker用户选择文件后立即履行的承诺.此时,我们可能仍需要通过网络下载所选文件.因此,我无法picker将所选文件作为分辨率值来实现.相反,picker应该用另一个承诺来实现downloadProgress,而这最终将通过所选文件来实现.

对于completenes,这是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;
}
Run Code Online (Sandbox Code Playgroud)

在标记线的问题是,我想履行承诺p1新的承诺p2,但我只知道如何解决它.履行和解决之间区别在于,如果提供的值p2再次成为承诺,则解析首先检查.如果是,则履行p1将被推迟到p2完成,然后p1将以p2分辨率值而不是p2其自身来实现.

我可以通过构建一个包装器来解决这个问题p2,即更换线路

        resolveP1(p2);  // <--- PROBLEM: I actually want to *fulfill* p1 with p2
Run Code Online (Sandbox Code Playgroud)

来自第二个代码示例

        resolveP1({promise: p2});
Run Code Online (Sandbox Code Playgroud)

然后,在第一个代码示例中,我必须替换该行

        return downloadProgress;
Run Code Online (Sandbox Code Playgroud)

通过

        return downloadProgress.promise;
Run Code Online (Sandbox Code Playgroud)

但是,当我真正想要做的只是履行(而不是解决)承诺时,这似乎有点像黑客.

我很感激任何建议.

rob*_*ler 1

除了我在问题中已经描述的解决方法之外,似乎没有其他解决方案。为了将来的参考,如果你想履行(而不是解决)一个p带有 value 的Promise val,其中另一个 Promise 是哪里,那么仅仅调用with argument 的valPromise 解析函数将无法按预期工作。它将导致“锁定” 的状态,这样一旦满足,就会满足 的分辨率值(参见规范)。pvalpvalpvalval

相反,包装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...
});
Run Code Online (Sandbox Code Playgroud)

如果您已经知道这val是一个承诺,则此解决方案有效。如果您无法对 的val类型做出任何假设,那么您似乎不走运。您必须始终将 Promise 解析值包装在另一个对象中,或者您可以尝试检测是否具有“function”类型的val字段并有条件地包装它。then

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