【问题标题】:The Javascript promise does not work as expectedJavascript 承诺没有按预期工作
【发布时间】:2017-10-25 13:13:49
【问题描述】:

在这里我宣布了我的承诺。

   const fetchmessage= new Promise(
            (resolve,reject)=>{
              this.props.authStore.verifyLocalToken();
              console.log("VLT Resolve");
              resolve("Completed");
            }
            );

          fetchmessage.then(this.props.inboxStore.inboxMessageFetch(mobileNumber,firebaseToken));

以下是我的verifyLocalToken代码

   verifyLocalToken() {
    console.log("VerifyLT - Start");
        fetch('http://xxx.xxx.xxx.xxx:8000/api/VerifyLocalToken', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            body: `mobileNumber=${this.mobileNumber}&key=${this.key}`
        }).then((response) => response.json()).then(
            (responseJson) => {
                console.log("http request v l t --", responseJson);
                this.firebaseToken = responseJson.firebaseToken;
            }).catch(
            (error) => {
                console.error(error);
            }
        )
        console.log("VerifyLT - Stop");

}

以下是我的 inboxMessageFetch 代码

inboxMessageFetch(mobileNumber,firebaseToken) {
        console.log("InboxFetch  --", `${mobileNumber}/inbox`,firebaseToken);

            firebase.database().ref(`${mobileNumber}/inbox`)
                .on('value', snapshot => {
                    console.log('FB', snapshot.val());
                })
    }

输出是这样的

不应该 http request v l t 在 InboxFetch -- 8891468710/inbox undefined 之前,因为 HTTP 请求属于 promise 和我们要求在获取 HTTP 请求后运行收件箱提取?

如何重构代码并确保HTTP请求完成,然后调用收件箱获取函数?

【问题讨论】:

  • 但是...这是一个 javascript 承诺
  • 是的,它是.. Javascript 承诺有什么问题?
  • 它按预期工作,你只是期望它像它不工作一样工作:) 否则,你声称 ES6 本机代码中存在一个基本错误,直到现在才不知何故被忽视?
  • 我不知道。我希望我的代码按预期运行。我找不到我的代码有任何问题。这就是为什么我问 SO,顺便说一下,我不明白为什么我的问题被否决了。我们不应该在 SO 上问这样的问题吗?
  • 不是真的,因为这是官方文档中解释的内容,这意味着您在发布之前没有进行研究。

标签: javascript ecmascript-6 es6-promise


【解决方案1】:

这里有几个问题。

  1. 线

    fetchmessage.then(this.props.inboxStore.inboxMessageFetch(mobileNumber,firebaseToken));
    

    ...调用 this.props.inboxStore.inboxMessageFetch(mobileNumber,firebaseToken) 并将其返回值传递给then,就像foo(bar()) 调用 bar 然后将其返回值传递给foo。您可能打算传入一个函数,例如

    fetchmessage.then(() => this.props.inboxStore.inboxMessageFetch(mobileNumber,firebaseToken));
    
  2. 在继续执行 fetchmessage 之前,您无需等待 verifyLocalToken 的异步工作完成。

  3. (与#2 相关)verifyLocalToken 不提供任何方式让调用者知道它的工作已完成;它需要返回一个承诺。

  4. (与 #2 和 #3 相关)您已经有一个承诺,来自 fetch,verifyLocalToken;因此无需创建新的 Promise 以保存在 fetchmessage 中。任何时候你有一个承诺,使用then,不要使用new Promise反模式。

  5. fetchmessage 对我来说听起来像是一个函数名,但在您的代码中,它是一个将接收承诺的变量,而不是一个函数。

以下是这些东西的大致外观(注意*** cmets):

verifyLocalToken() {
    console.log("VerifyLT - Start");
    // *** Return the promise from `then`
    return fetch('http://xxx.xxx.xxx.xxx:8000/api/VerifyLocalToken', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: `mobileNumber=${this.mobileNumber}&key=${this.key}`
    }).then((response) => response.json()).then(
        (responseJson) => {
            console.log("http request v l t --", responseJson);
            this.firebaseToken = responseJson.firebaseToken;
        }).catch(
        (error) => {
            console.error(error); // *** You're converting failure to success
                                  // with `undefined` here, which isn't
                                  // a good idea. Re-throw the error.
            throw error;
        })
    // *** If you want to show something when this finishes, do it
    // in a `then` handler
    ).then(value => {
        console.log("VerifyLT - Stop");
        return value;
    });
}

然后fetchmessage:

const fetchmessage = this.props.authStore.verifyLocalToken()
    .then(value => {
        console.log("VLT Resolve");
        return "Completed"; // *** Really convert the value to completed?
    });

...如果你想单独调用then:

fetchmessage.then(result => this.props.inboxStore.inboxMessageFetch(mobileNumber, firebaseToken));

这是你需要做的一个草图,不是意味着直接复制和粘贴。仔细考虑更改并在必要时应用它们。

请记住,promise 是一个管道,每个处理程序都可以在其中转换值。

【讨论】:

    【解决方案2】:
          fetchmessage.then(this.props.inboxStore.inboxMessageFetch(mobileNumber,firebaseToken));
    

    这段代码是直接调用inboxMessageFetch函数而不是等待then。我认为正确的代码是

    fetchmessage.then(() =>      
        this.props.inboxStore.inboxMessageFetch(mobileNumber,firebaseToken);
    )
    

    【讨论】:

      【解决方案3】:

      你不需要做出新的承诺,但你确实需要从你的方法中返回承诺,你的 verifyLocalToken 方法应该是这样的

       verifyLocalToken() {
          return fetch('http://xxx.xxx.xxx.xxx:8000/api/VerifyLocalToken', {
                  method: 'POST',
                  headers: {
                      'Content-Type': 'application/x-www-form-urlencoded'
                  },
                  body: `mobileNumber=${this.mobileNumber}&key=${this.key}`
              }).then((response) => response.json()).then(
                  (responseJson) => {
                      console.log("http request v l t --", responseJson);
                      this.firebaseToken = responseJson.firebaseToken;
                  }).catch(
                  (error) => {
                      console.error(error);
                  }
              )
              console.log("VerifyLT - Stop");
      
      }
      

      那么你就可以这样做了

      const fetchmessage = this.props.authStore.verifyLocalToken();
      fetchmessage.then(() => {
          this.props.inboxStore.inboxMessageFetch(mobileNumber,firebaseToken));
      }
      

      【讨论】:

        猜你喜欢
        • 2018-09-19
        • 2019-12-03
        • 2013-06-05
        • 1970-01-01
        • 1970-01-01
        • 2017-01-16
        • 2019-02-05
        • 2018-02-13
        • 2021-03-27
        相关资源
        最近更新 更多