JavaScript - 返回承诺和/或调用回调?

Posted

技术标签:

【中文标题】JavaScript - 返回承诺和/或调用回调?【英文标题】:JavaScript - Return promise AND/OR call callback? 【发布时间】:2016-08-18 16:33:39 【问题描述】:

我经常在其他人的文档中看到类似的内容:

回调是可选的,如果省略则返回一个承诺。

这就是我所拥有的:

export function doSomeAsync(options, callback) 

    const useCallback = (callback && typeof callback == 'function');

    const promise = new Promise((resolve, reject) => 

        // --- do async stuff here ---
        const check = (options.num === 1) ? true : false;
        setTimeout(() => 
            if (check) 
                finish(true, "Number is 1");
             else 
                finish(false, new Error("Number is not 1"));
            
        , 1000);
        // ---------------------------

        function finish(ok, rtn) 
            if (useCallback) 
                if (ok) 
                    callback(null, rtn);
                 else 
                    callback(rtn, null);
                
             else 
                if (ok) 
                    resolve(rtn);
                 else 
                    reject(rtn);
                
            
        

    );

    return (useCallback) ? false : promise;

finish() 函数只是避免了散布在各处的大量 if... 语句。

我正在创建一个 Promise 对象,无论我是否使用它。

像这样测试:

doSomeAsync( num: 1 ).then((result) => 
    console.log('p result', result);
).catch((err) => 
    console.log('p err', err);
);

doSomeAsync( num: 1 , (err, result) => 
    if (err) 
        console.log('cb err', err);
     else 
        console.log('cb result', result);
    
);

这可行,但我想知道这是否是最好的方法,或者其他人是否有更好、更简洁的实现..?

【问题讨论】:

可能更适合codereview.stackexchange.com 你使用的是什么承诺库? Bluebird 甚至为此提供了 a dedicated function。 我正在运行 Node v4.2.2,使用 Babel for ES6 (babel-preset-es2015 6.6.0),但我还没有为 Promise 安装特定的 babel ployfill。所以我猜是原生 Node 承诺。 【参考方案1】:

您可以通过始终返回一个承诺来摆脱所有边缘情况,并定义一个默认回调(一个回调形状的标识函数)来处理不提供回调的情况:

const genericAsync = (stuff, callback = (e, i) => e || i) => new Promise(
  (resolve, reject) => doStuffWith(stuff, resolve, reject)
)
  .then(response => callback(null, response))
  .catch(callback);

【讨论】:

【参考方案2】:

如果你总是简单地使用你总是在创建的承诺,这可以简化:

export function doSomeAsync(options, callback) 
    const promise = new Promise((resolve, reject) => 
        const check = (options.num === 1) ? true : false;
        setTimeout(() => 
            if (check) 
                resolve("Number is 1");
             else 
                reject(new Error("Number is not 1"));
            
        , 1000);
    );

    if (callback && typeof callback == 'function') 
        promise.then(callback.bind(null, null), callback);
    

    return promise;

你的函数总是基于 Promise 的,事实上它总是返回一个 Promise。调用者可以随意忽略它。回调参数只是使用该承诺的“遗留后备接口”(或“替代接口”,如果您愿意的话)。

【讨论】:

是的,这正是我所想的方法。返回 false 似乎有点浪费——而且(作为 .NET 开发人员和 JS)从这样的函数返回两种不同的类型似乎很奇怪。 谢谢 deceze... 我已经用测试电话更新了我的问题。更新以使用您的代码后,我得到:p result Number is 1cb err Number is 1。回调现在是否只有一个参数? @Stephen 在我上面的示例中,promise.then 回调绑定的方式,callback 将在成功的情况下接收一个参数,在失败的情况下接收两个参数(false 和错误) .回调应该有function (result, err) 的签名。以您喜欢的方式设计该界面。 我注意到答案已更新为 promise.then(callback.bind(null, null), callback) 以生成我正在寻找的节点样式 callback(err, result)。谢谢Bergi & deceze!

以上是关于JavaScript - 返回承诺和/或调用回调?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建从回调函数返回承诺的函数[重复]

承诺回调返回承诺

javascript 回调,承诺和异步/等待

Node.js 从函数返回一个承诺

ES6新特性之 promise

异步 JavaScript - 回调与延迟/承诺 [重复]