从承诺中返回一个值:回调还是承诺?

Returning a value from a promise: callback or promise?

(* 我修改了我最初的问题... *)

我有一个异步函数 calculate,它重新计算 Excel 工作簿并打印它需要多长时间。

然后,我想把函数做成return计算时间,这样我就可以记录下来。它考虑使一个异步函数 return 成为一个值。我阅读了几个线程,并编写了以下两种有效的方法:

function calculate1 (mode, fn) {
    return Excel.run(function (ctx) {
        ctx.workbook.application.calculate(mode);
        var before = performance.now();
        return ctx.sync().then(function() {
            var after = performance.now();
            var t = after - before;
            document.getElementById("b").value += 'inside: ' + t + '\n'; 
            fn(t);
        })
    })
}

function calculate2 (mode) {
    return new Promise(function (resolve, reject) {
        return Excel.run(function (ctx) {
            ctx.workbook.application.calculate(mode);
            var before = performance.now();
            return ctx.sync().then(function() {
                var after = performance.now();
                var t = after - before;
                document.getElementById("b").value += 'inside: ' + t + '\n';
                resolve(t); })
            })
    })
}

这是测试:

function test () {
    var a = [];
    var pm = new OfficeExtension.Promise(function(resolve, reject) { resolve (null); });

    pm
        .then(function() { return calculate1('FullRebuild', function (t) {
            a.push(t); }); })
        .then(function() { return calculate1('FullRebuild', function (t) {
            a.push(t); }); })
        .then(function() { return calculate2('FullRebuild').then(function (result) {
            a.push(result); }); })
        .then(function() { return calculate2('FullRebuild').then(function (result) {
            a.push(result); }); })
        .then(function() {
            document.getElementById("b").value += a.toString() + '\n'; });
}

我猜 calculate1 使用 callback,而 calculate2 使用 promise。谁能告诉我哪种方式更好?

此外,fn(t)(相应的,resolve(t))在正确的位置,还是我应该将其包装在另一个 then 中?

PS:Excel.runctx.sync()JavaScript API for Office的函数;他们都return一个承诺。

calculate1() 是 promises 和回调的糟糕组合,而 calculate2() 展示了 Explicit Promise Construction Antipattern.

以下是正确使用 promises 而不会造成任何额外浪费的方法:

function calculate1 (mode) {
    return Excel.run(function (ctx) {
        ctx.workbook.application.calculate(mode);
        var before = performance.now();

        return ctx.sync().then(function() {
            var after = performance.now();
            var t = after - before;
            document.getElementById("b").value += 'inside: ' + t + '\n'; 

            return t;
        });
    });
}

然后就可以这样消费了。请注意,它使用的函数比您尝试的要少得多:

return calculate1('FullRebuild')
    .then(function(res) { 
        a.push(res);
        return calculate1('FullRebuild'); 
     })
    .then(function(res) { 
        a.push(res);
        return calculate1('FullRebuild'); 
     })
    .then(function(res) { 
        a.push(res);
        return calculate1('FullRebuild'); 
     })
    .then(function(res) {
        a.push(res);
        document.getElementById("b").value += a.toString() + '\n'; 
    });

如果您想要一个异步函数 return 一个值 - 而不是将回调传递给它 - return 值需要包装在一个承诺中并像第二个示例中那样解析。

promise 的便利在于它避免了回调嵌套 -> 当一个回调需要另一个回调时... 错误传播到最近的 Promise.catch() 块

的方式
function calculate2 (mode) {
    return new Promise(function (resolve, reject) { 

        Excel.run(function (ctx) {       
           ctx.workbook.application.calculate(mode);
           var before = performance.now();

           ctx.sync().then(function() { 
               var after = performance.now(); 
               var t = after - before;  

               resolve(t); 
            })
        })
    })
}

calculate2('FullRebuild')
    .then(function (t) {
         document.getElementById("b").value += 'inside: ' + t + '\n';
         // the return value of a promise resolver is wrapped in a promise too
         // and the value of t will be available as parameter of the following .then(funtion(t)) block
         return t; 
 })
.catch(function(err) {
    // Addresses potential async errors raised since calling calculate2()
 });