【问题标题】:How to convert to using Promises and Q Library如何转换为使用 Promises 和 Q 库
【发布时间】:2017-04-04 04:56:36
【问题描述】:

我们有一个正在增长的应用程序,我们的客户端脚本需要重构,使其更简洁、更精简和更易于维护。我正在尝试将一个小模块用于利用 Q 库进行承诺链接。

如您所见,我需要将一些返回值从初始函数传递回承诺链的其余部分。 有人可以帮我理解我需要做什么才能让第一个函数作为 Promise 正确返回吗?然后解释链条?

这是我的出发点:

var promise = new Q.Promise(generateMoveRequest)
    .then(function (id) {
       var woNum = 12345;
       return layoutInit(woNum, id, true);
    }).then(function (result) {
        if (result) {
          return moveRequestInit(result, true);
        } else { 
          throw new Error('Template not loaded');
        }
    }).catch(function (err) {
        console.log(err);
    });

生成移动请求:

generateMoveRequest: function () {
        $.ajax({
            method: "GET",
            url: window.contextPath + '/api/settings/getjson',
            data: {name: "the_name"},
            success: function (data) {
                if (data.length) {
                    var id = $.parseJSON(data).Parent;                                          
                    return id;
                }
            },
            error: function (xhr, textStatus, errorThrown) {
                console.log("xhr: ", xhr);
                return null;
            }
        });
    }

布局初始化:

layoutInit: function (num, id, appendLayout) {
    $.ajax({
            method: "GET",
            url: window.contextPath + '/some/url',
            data: {num: num, id: id},
            success: function (data) {
                return layoutInit.callback(data, appendLayout);
            },
            error: function (xhr, textStatus, errorThrown) {
                console.log("xhr: ", xhr);
            }
        });
    },
    callback: function (data, appendLayout) {
        if (data && data.toString().toLowerCase() !== "blank") {
            if (appendLayout) {
                $(data).insertBefore($("#detailsection"));
            } else {
                $("#detailsection").html(data);
            }                               
        } else {
            $("#detailsection").html('');
        }
    },

generateMoveRequest 函数将执行,但链不再继续。没有 .then() 执行和 layoutInit 永远不会被调用。

我正在使用 Q 库,但其中一些示例似乎忽略了如何启动/创建 Promise 或将初始函数转换为 Promise。

有人可以解释我在这里有什么问题或提供一个干净的例子吗?

【问题讨论】:

  • 你的函数generateMoveRequest应该返回一些东西:$.ajax返回一个promise(它有一个then方法),所以你可以直接返回。
  • @trincot 我让它返回一个值 => id
  • 那是成功回调的返回值,而不是函数generateMoveRequest的返回值。

标签: javascript jquery promise q


【解决方案1】:

promise 的 jQuery 实现不遵循 A+ 标准,所以最好使用 Q。

promise 必须接收一个带有 2 个参数的函数 - resolvereject - 这也是函数(请记住 Javascript 是一种函数式语言)。 resolve 函数必须在成功时调用,reject 在错误时调用。你传递给这些函数的任何东西都将在then()catch() 回调中可用。

长话短说,像这样重写你的代码:

var generateMoveRequest = function (resolve, reject) {
  $.ajax({
    method: "GET",
    url: window.contextPath + '/api/settings/getjson',
    data: {name: "the_name"},
    success: function (data) {
      if (data.length) {
        var id = $.parseJSON(data).Parent;
        resolve(id);
      } else {
        reject({message: 'Data not received'})
      }
    },
    error: function (xhr, textStatus, errorThrown) {
      reject({message: errorThrown})
  }
  });
}

var promise = new Q.Promise(generateMoveRequest)
    .then(function (id) {
       var woNum = 12345;
       return layoutInit(woNum, id, true);
    }).then(function (result) {
        if (result) {
          return moveRequestInit(result, true);
        } else {
          throw new Error('Template not loaded');
        }
    }).catch(function (error) {
      console.log(error.message)
    });

稍后编辑 - 查看 sn-p 以了解 Promise 的工作原理:

// any number of params
function willPerformAnAsyncOperationAndReturnAPromise(firstParam, secondParam, thirdParam) {
  var promise = new Q.Promise(function (resolve, reject) { // always resolve & reject
    // perform an async operation, like waiting one second
    window.setTimeout(function () {
      if (firstParam !== 0) {
        // if the 1st param is not 0, it's a success
        resolve ({
          first: firstParam,
          second: secondParam,
          third: thirdParam
        })
      } else {
        reject({message: 'The first param must not be null'})
      }
    }, 1000)
  })

  return promise
}

willPerformAnAsyncOperationAndReturnAPromise(1, 2, 3)
  .then(function (data) {
    console.log(data)
  })
  .catch(function (error) {
    console.log(error)
  })

willPerformAnAsyncOperationAndReturnAPromise(0, 2, 3)
  .then(function (data) {
    console.log(data)
  })
  .catch(function (error) {
    console.log(error)
  })

【讨论】:

  • 谢谢。非常感激!我现在意识到任何 Promise 函数都必须明确地解析和拒绝。现在更有意义了。在那之后就像一个魅力。
  • 它有效,但它使用promise constructor antipattern,因为$.ajax 已经是一个承诺。
  • 请注意,从 jQuery 3.0 开始,jQuery 的 Promises 实现是 A+ conformant
  • 如果我有一个函数是一个 promise 但需要 2 个参数怎么办?例如:generateMoveRequest(param1, param2)。它是否需要一个 Wrapped 来承诺和链接?
  • @Encryption 在您的情况下,generateMoveRequest 是您包装在承诺中的异步操作,并且始终采用 2 个参数。我在原始答案中添加了解释,以便您更好地理解。 @trincot 如果最初的承诺不是 A+,那么它不是反模式。现在最好将其包装为兼容的类型,因为以后很容易重构
【解决方案2】:

一些问题:

  • 你的函数generateMoveRequest应该返回一些东西:$.ajax返回一个promise(它有一个then方法),所以你可以直接返回它;

  • 您不需要创建新的承诺,因为generateMoveRequest 返回一个。这样可以避免promise constructor anti-pattern

建议代码:

generateMoveRequest: function () {
    return $.ajax({
        method: "GET",
        url: window.contextPath + '/api/settings/getjson',
        data: {name: "the_name"},
    }).then(function (data) {
        if (data.length) {
            var id = $.parseJSON(data).Parent;                                          
            return id;
        }
    }).catch(function (xhr, textStatus, errorThrown) {
        console.log("xhr: ", xhr);
        return null;
    })
}

var promise = generateMoveRequest()
    .then(function (id) {
        var woNum = 12345;
        return layoutInit(woNum, id, true);
    }).then(function (result) {
        if (result) {
           return moveRequestInit(result, true);
        } else { 
           throw new Error('Template not loaded');
        }
    }).catch(function (err) {
        console.log(err);
    });

【讨论】:

  • 投反对票的人能否发表评论,让我知道我错过了什么?
猜你喜欢
  • 2013-09-28
  • 1970-01-01
  • 2017-03-07
  • 2014-07-03
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 2016-11-05
  • 2016-05-26
相关资源
最近更新 更多