【问题标题】:Compound Promises in Typescript / Javascript?Typescript / Javascript中的复合承诺?
【发布时间】:2016-05-28 12:29:03
【问题描述】:

我正在编写一个基于 Angular2 的移动应用程序,将 Typescript 与 Nativescript 运行时结合使用,但在使用 Promises 时遇到了一些问题。我有一个 HomeComponent,我希望能够从中调用各种蓝牙功能。这些需要人工交互(如选择设备)和蓝牙扫描的等待时间,因此它们需要几秒钟才能完成。

我想将这些方法抽象为promise,所以我这样做了:

HomeComponent.ts:

bluetoothAdd() {
    this.isScanning = true;
    this._ble.scan().then(
        // Log the fulfillment value
        function (val) {
            this.isScanning = false; //hide activity indicator
            this.Connect(this.ble._peripheral);
        })
        .catch(
        function (reason) {
            this.isScanning = false; //hide activity indicator
            console.log('Handle rejected promise (' + reason + ') here.');
        });
}

BluetoothUtils.ts(这是上面导入的this._ble):

var devices: Array<string>;
var _peripheral: any;

export function scan() {
    return new Promise((resolve, reject) => {
        bluetooth.hasCoarseLocationPermission().then(
            (granted) => {
                if (!granted) {
                    bluetooth.requestCoarseLocationPermission();
                } else {
                    bluetooth.startScanning({
                        serviceUUIDs: ["133d"],
                        seconds: 4,
                        onDiscovered: (peripheral) => {
                            console.log("Periperhal found with UUID: " + peripheral.UUID);
                        }
                    }).then(() => {
                        console.log("scanning complete");

                    }, (err) => {
                        console.log("error while scanning: " + err);
                    });
                }
            });
    });
}

使用调试器逐步完成我的应用程序后,当在我的 HomeComponent 中调用 bluetoothAdd() 时,我在 BluetoothUtils 中的 scan() 函数按预期工作,在一种情况下,执行 console.log("error while scanning: " + err); 行,说:

扫描时出错:蓝牙未启用

但是,HomeComponent this._ble.scan() 承诺的 thencatch 部分都没有执行?为什么是这样?你能像我试图做的那样复合 Promises(即 Promise 中的 Promise)吗?或任何想法如何进一步调试?

【问题讨论】:

  • 避免使用Promise constructor antipattern!请注意,您甚至没有在任何地方调用 resolvereject,这就是为什么 .scan() 返回的承诺永远不会解决。

标签: javascript typescript angular promise nativescript


【解决方案1】:

有一些问题。

1/ 您使用的是anti pattern。无需在 scan 中创建新的 Promise,因为您处理的只是 Promise。

2/a) 如果你想使用反模式,你需要调用 resolvereject 函数,即在当前情况下,新的承诺永远不会被解决或拒绝,因此“主要” scan 中的 promise 也永远不会被解决或拒绝。

2/b) 更好的解决方案:简单地返回已经创建的承诺。如果您不返回,它们将成为单独的承诺分支,并且不会影响 scan 中的“主要”承诺分支,即:

export function scan() {
    return bluetooth.hasCoarseLocationPermission().then(
        (granted) => {
            if (!granted) {
                return bluetooth.requestCoarseLocationPermission();
            } else {
                return bluetooth.startScanning({
                    serviceUUIDs: ["133d"],
                    seconds: 4,
                    onDiscovered: (peripheral) => {
                        console.log("Periperhal found with UUID: " + peripheral.UUID);
                    }
                }).then(() => {
                    console.log("scanning complete");

                }, (err) => {
                    console.log("error while scanning: " + err);
                });
            }
        });
}

注意添加的 3 个 returns:一个在 scan 的顶部,然后在 bluetooth.requestCoarseLocationPermissionbluetooth.startScanning 之前

如果你想知道还有哪些 promise 反模式,here's a great resource

【讨论】:

  • 谢谢。所以如果我按照你的建议 2b,我的 HomeComponent 代码会是什么样子?
  • 完全一样。除非this.Connect 也返回一个promise 并且 你希望它在同一个promise 分支中处理,在这种情况下你也应该return 它。
【解决方案2】:

由于您正在使用 typescript,请不要再等待await/async。尤其是当您有多个承诺时,它会更加清晰。

async function bluetoothAdd() {
    this.isScanning = true;
    try {
        const val = await this._ble.scan();
        this.Connect(this.ble._peripheral);
    } catch (reason) {
        console.log('Handle rejected promise (' + reason + ') here.');
    }finally{
        this.isScanning = false;
    }
}


//Bluetoo.....ts
var devices: Array<string>;
var _peripheral: any;

export async function scan() {
    const granted = await bluetooth.hasCoarseLocationPermission();
    if(!granted){
        return bluetooth.requestCoarseLocationPermission();
    }else{
        try {
            const val = await bluetooth.startScanning({
                    serviceUUIDs: ["133d"],
                    seconds: 4,
                    onDiscovered: (peripheral) => {
                        console.log("Periperhal found with UUID: " + peripheral.UUID);
                    }
                });
            console.log("scanning complete");
            return val;
        } catch (err) {
            // you can rethrow err here such that user `bluetoothAdd` will recieve it/
            console.log("error while scanning: " + err);
        }
    }
}

【讨论】:

    【解决方案3】:

    看起来第一个 then 中的代码没有返回任何内容,即您没有返回承诺。我希望看到像 return bluetooth.startScanning(..) 这样的东西。你当然可以嵌套 Promise,但将它们链接起来更具可读性。 IE。将 console.log 的 then 移到与上一个 then 相同的嵌套级别。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-21
      • 2015-11-04
      • 2016-03-09
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      相关资源
      最近更新 更多