【问题标题】:JavaScript - Return promise AND/OR call callback?JavaScript - 返回承诺和/或调用回调?
【发布时间】: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);
    }
});

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

【问题讨论】:

  • 你使用的是什么承诺库? Bluebird 甚至为此提供了 a dedicated function
  • 我正在运行 Node v4.2.2,使用 Babel for ES6 (babel-preset-es2015 6.6.0),但我还没有为 Promise 安装特定的 babel ployfill。所以我猜是原生 Node 承诺。

标签: javascript callback promise


【解决方案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!
    猜你喜欢
    • 1970-01-01
    • 2016-06-15
    • 2016-07-23
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-22
    相关资源
    最近更新 更多