如何在交互式调用中使用承诺?

How to use promises in an interactive call?

我正在检索表单(通过 XMPP、XEP-0004),为其创建交互式表单对话框,然后在对话框关闭时提交表单。

代码(为简单起见大致近似):

function form(name, callback) {
  server.getForm(name, function(response) {
    callback(response.formFields, function (data) {
      server.submitForm(name, data);
    });
  });
}

function main() {
  form('example', function(fields, callback) {
    var dialog = ui.formDialog(fields);
    dialog.addButton('submit', function(data) {
      callback(data);
    });
    dialog.show();
  });
}

注意调用者和被调用者如何交换回调——在一个方向上,对于从服务器检索的字段;另一方面,对于用户提交的数据。

我最近发现了 JS Promises,我想知道它们是否可以更优雅地替换回调。

我得到了:

function form(name) {
  return new Promise((resolve, reject) => {
    server.getForm(
      name,
      (response) => { resolve(response.formFields) },
      reject
    );
  });
}

function main() {
  form('example').then((fields) => {
    var dialog = ui.formDialog(fields);
    dialog.addButton('submit', /* ... */);
  });
}

但现在我卡住了,因为我无法将提交按钮的事件传递回 form() 调用。

我也不能简单地为对话框创建 Promise,因为我必须先创建该 Promise 才能将其传递给 form(),但我需要 [=12] 返回的 Promise =] 在我创建对话框之前解决。有一种 bootstrap 问题。

这里有什么方法可以使用 promise,还是我应该坚持来回传递回调?

您仍然可以在响应中传递回调。只需将响应和回调数组传递给 resolve。在 .then 回调中,您可能会破坏数组。简而言之,您可以这样写:response => resolve([response.formFields, **your_callback**]).then(([fields, callback]) ...。但在我看来,代码很臭,你应该将 from 函数分解为两个独立的函数,以避免来回传递回调

您可以将问题分为三个部分:

  1. form - 检索表单 - 采用名称和 returns Promise 的函数使用字段解析。
  2. askUser - 收集输入 - 接受字段、显示表单和 return 提交数据的 Promise 的函数。
  3. submit - 提交表单 - 获取数据的函数,return 是网络结果的承诺。

你可以将三者组合在一起:

form('example')
  .then(askUser)
  .then(submit)
  .catch(errorHandler)

哪个 return Promise 最终会通过提交操作解决。

form 将其行为包装在回调周围,如果不将 form 拆分为两个函数,就无法真正避免该回调。但是,它完全没问题 - 它被称为 .

您可以这样使用它:

function form(name, callback) {
  return server.getForm(name).then(function(response) {
    return callback(response.formFields);
  }).then(function (data) {
    return server.submitForm(name, data);
  }).catch(function(e) {
    console.error(e); // or display it in the form, or whatever
  });
}

function main() {
  return form('example', function(fields) {
    return new Promise(function(resolve, reject) {
      var dialog = ui.formDialog(fields);
      dialog.addButton('submit', resolve);
      dialog.show();
    });
  });
}