【问题标题】:Chaining function with then doesn't work correctly与 then 的链接功能无法正常工作
【发布时间】:2019-03-06 06:32:29
【问题描述】:

嘿,我遇到了一个问题,与 .then 链接的函数不能正常工作,而不是按应有的顺序工作。

我的代码:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>

    <script>
      var users = [];
      var user = null;

      function restCallA() {
        return $.ajax({
          url: "https://reqres.in/api/users?page=2",
          type: "GET",
          success: function(response) {
            users = response.data;
            console.log("users", users);
          }
        });
      }
      function restCallB() {
        return $.ajax({
          url: "https://reqres.in/api/users/2",
          type: "GET",
          success: function(response) {
            user = response.data;
            console.log("user", user);
          }
        });
      }
      function myFun(testArg) {
        users.push(user);
        console.log("why users is null?", testArg, users);
      }

      $(function() {
        restCallA()
          .then(restCallB)
          .then(myFun("test"));
      });
    </script>
  </body>
</html>

输出:

myFun 函数上的用户变量应该包含第一个 restCall 中的所有数据,并将第二个 restCall 中的数据推送到同一个变量。 变量确实获取了数据,但 myFun 函数在它们之前运行,因此其中的 users 变量为空。

结果图片:

我该如何解决这个问题?

【问题讨论】:

    标签: javascript ajax rest promise


    【解决方案1】:

    .then 接受一个函数作为参数,但在

    restCallA()
      .then(restCallB)
      .then(myFun("test"));
    

    您正在调用 myFun,并将其返回值传递给第二个.then。它评估为:

    restCallA()
      .then(restCallB)
      .then(undefined);
    

    myFun立即运行,而解释器尝试将 Promise 链放在一起(在响应返回之前)。

    传递一个调用 myFun 的函数:

    restCallA()
      .then(restCallB)
      .then(() => myFun("test"));
    

    您也可以使用.bind,它将创建一个带有所需参数的函数,但不会调用它:

    restCallA()
      .then(restCallB)
      .then(myFun.bind(undefined, "test"));
    

    var users = [];
    var user = null;
    
    function restCallA() {
      return $.ajax({
        url: "https://reqres.in/api/users?page=2",
        type: "GET",
        success: function(response) {
          users = response.data;
          console.log("users", users);
        }
      });
    }
    
    function restCallB() {
      return $.ajax({
        url: "https://reqres.in/api/users/2",
        type: "GET",
        success: function(response) {
          user = response.data;
          console.log("user", user);
        }
      });
    }
    
    function myFun(testArg) {
      users.push(user);
      console.log("why users is null?", testArg, users);
    }
    
    $(function() {
        restCallA()
          .then(restCallB)
          .then(() => myFun("test"));
    });
    &lt;script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"&gt;&lt;/script&gt;

    如果函数返回一个函数,则仅在.then的参数列表中调用一个函数,例如:

    const fnThatReturnsFn = arg => resolveValue => console.log(arg, resolveValue);
    someProm()
      .then(fnThatReturnsFn('somearg'));
    

    【讨论】:

      【解决方案2】:

      $.ajax 返回一个类似 Promise 的对象。因此,通过在函数中的 then 中返回来自 ajax 调用的数据,利用它来发挥您的优势。

      请注意,我已使用 @CertainPerformance's suggestions in their answer 之一来修复 myFun 问题。

      <html lang="en">
      
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
      </head>
      
      <body>
        <script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
      
        <script>
          function restCallA() {
            return $.ajax({
              url: "https://reqres.in/api/users?page=2",
              type: "GET"
            }).then(response => response.data);
          }
      
          function restCallB(users) {
            return $.ajax({
              url: "https://reqres.in/api/users/2",
              type: "GET"
            }).then(response => {
              return {
      // ES2015 method for adding a property named "users" with the value of the users variable
                users, 
                user: response.data
              };
            });
          }
      
          function myFun(testArg, usersAndUser) {
            usersAndUser.users.push(usersAndUser.user);
            console.log(testArg);
          }
      
          $(function() {
            restCallA()
              .then(restCallB)
              .then((usersAndUser) => myFun("test", usersAndUser));
          });
        </script>
      </body>
      
      </html>

      请注意,我使用一个对象将usersuser 收集到一个对象中;您可以轻松地使用数组。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-23
        • 2021-02-27
        • 2012-12-27
        • 2013-11-06
        • 2013-10-29
        相关资源
        最近更新 更多