簡體   English   中英

javascript返回一個promise的麻煩 - 返回的promise沒有執行

[英]javascript trouble with returning a promise- the returned promise is not executing

我有一個看起來像這樣的功能

this.getToken = function() {
    if (token === null) {
        token = getAccessTokenAsync("username", "password");
        lastTokenTime = getTokenExpiryAsync();
    }
}

此函數將調用getAccessTokenAsync,它將使用xhr向我的Web服務器發出請求。 這看起來像這樣:

getAccessTokenAsync = function (username, password) {
    var serializedData = {
        username: username, password: password,
    };

    return new WinJS.Promise(function (complete) {
        WinJS.xhr({
            type: "post",
            url: "http://127.0.0.1:8080/authenticate/login",
            responseType: "json",
            data: JSON.stringify(serializedData)
        }).done(
            function complete(result){
                return JSON.parse(result.responseText);
            }
        );
    })
}

我希望令牌現在可以存儲一個承諾。 當我們調用.done().next()時會有服務器返回的json對象。 但是當我調用getTokenExpiryAsync()時會發生其他事情。

getTokenExpiryAsync = function () {
    if (token === null) {
        return new Date();
    }

    token.then(
        function complete(result){
            console.log(result);
        },
        function onerror(error) {
            console.log(error);
        },
        function onprogress(data) {
        });
}

相反它似乎沒有調用.then()中的任何函數它只是跳過它! 啟用了嚴格模式,因此我的令牌變量在其中具有承諾。 否則它會出錯,因為它無法找到.done()方法?

我的問題是為什么這是happerning,我怎么能得到我想要的預期行為(令牌從getAccessTokenAsync存儲在其中的承諾,我可以在其他方法中訪問)。

在您的代碼中,沒有必要創建一個新的WinJS.Promise,因為WinJS.xhr()。然后將返回您想要的承諾。 為了給出背景,有兩種方法可以將完成的處理程序附加到一個promise:.then和.done。 兩者都采用相同的參數,但返回值不同。 .done返回undefined,因為它意味着在promise鏈的最后使用。

另一方面,返回一個在完成(或錯誤處理程序)返回時滿足的promise,並且履行值是從已完成的處理程序(或錯誤處理程序)返回的值。

(順便說一下,我已經寫了很多關於承諾來澄清這樣的問題。可以找到一個簡短的版本所有關於promises (Windows開發博客);更完整的版本可以在附錄A中找到,“揭秘承諾, “我的免費電子書, 用HTML,CSS和JavaScript編寫Windows應用商店應用程序,第二版 ,這是它現在的第二次預覽。)

在編寫自己的任何異步函數時,調用其他現有異步函數(如WinJS.xhr)時使用的最佳模式是從其.then返回一個promise。 所以在你的情況下,你希望getAccessTokenAsync看起來像這樣:

getAccessTokenAsync = function (username, password) {
    var serializedData = {
        username: username, password: password,
    };

    return WinJS.xhr({
            type: "post",
            url: "http://127.0.0.1:8080/authenticate/login",
            responseType: "json",
            data: JSON.stringify(serializedData)
        }).then(
            function complete(result){
                return JSON.parse(result.responseText);
            }
        );
    })
}

這將返回一個promise,您分配給token,其履行值將是JSON.parse(result.responseText)的結果。

現在讓我解釋為什么你最初使用新的WinJS.Promise是不正確的 - 這是一個常見的誤解,我的其他着作清晰。 你在這里給構造函數賦予的函數參數接收三個參數。 每個參數都是另一個函數,我稱之為“調度程序”,你得到一個完整,錯誤和進度的函數。 承諾中的代碼主體會在適當的事件上調用這些調度程序。

然后,這些調度程序會調用已完成的,錯誤的和進度處理程序,以便通過promise的.then或.done訂閱任何函數。 換句話說,調用這些調度程序是實際觸發對這些處理程序的調用的唯一方法。

現在,在原始代碼中,您實際上從未調用任何這些代碼。 通過讓WinJS.Promise構造函數只關注已完成的調度程序,您可以保持簡單。 但是,當您的WinJS.xhr調用完成后,您不會調用此調度程序。 令人困惑的部分原因是你有一個名為complete的參數,然后為WinJS.xhr()命名你已完成的處理程序。完成“完成”。 如果你在最后一次JSON.parse調用中設置斷點,它應該被命中,但是你的返回值只會被吞下,因為它永遠不會傳遞給完整的調度程序

要更正此問題,您希望原始代碼如下所示:

return new WinJS.Promise(function (completeDispatch) {  //Name the dispatcher for clarity
    WinJS.xhr({
        type: "post",
        url: "http://127.0.0.1:8080/authenticate/login",
        responseType: "json",
        data: JSON.stringify(serializedData)
    }).done(
        function (result) {  //Keep this anonymous for clarity
            completeDispatch(JSON.parse(result.responseText));
        }
    );
})

這也應該有效。 但是,最簡單的方法就是從WinJS.xhr()返回承諾。然后像我最初注意到的那樣,因為你根本不需要另一個promise包裝器。

通過這些更改之一,您現在應該在getTokenExpiryAsync中看到對已完成的處理程序的調用。

我們現在來談談代碼的其他部分。 首先,即使存在錯誤條件,也會始終將令牌設置為承諾,因此您將永遠不會在getTokenExpiryAsync中看到空案例。 其次,如果您使用上面的新WinJS.Promise代碼,您將永遠不會看到錯誤或進度情況,因為您永遠不會調用errorDispatcher或progressDispatcher。 這是使用WinJS.xhr()。then()的返回的另一個好理由。

所以你需要在這里仔細考慮你的錯誤處理。 確切地說,您希望為到期日調用新的Date()的情況是什么? 當xhr調用失敗,或者成功調用的響應返回空時,您是否這樣做?

處理錯誤的一種方法是使用上面的新WinJS.Promise變體,使用WinJS.xhr()。done(),在其中為.done訂閱錯誤處理程序。 在該錯誤處理程序中,您可以通過調用completeDispather(new Date());來確定是否要傳播錯誤,或者是否仍希望使用新Date來實現包裝器承諾。 對於其他錯誤,您將調用errorDispatcher。 (請注意,所有這些都假定成功的xhr響應包含與新Date()相同的數據格式,否則您將混合數據值並希望解析響應中的日期而不是僅返回整個響應。)

return new WinJS.Promise(function (completeDispatch) {  //Name the dispatcher for clarity
    WinJS.xhr({
        type: "post",
        url: "http://127.0.0.1:8080/authenticate/login",
        responseType: "json",
        data: JSON.stringify(serializedData)
    }).done(
        function (result) {  //Keep this anonymous for clarity
            completeDispatch(JSON.parse(result.responseText));
        },
        function (e) {
            completeDispatch(new Date());  //Turns an xhr error into success with a default.
        }
    );
})

我剛剛描述的是一個很好的方法來捕獲核心操作中的錯誤,然后注入一個默認值,這是我認為你打算的。

如果你使用WinJS.xhr()。then()的返回值,另一方面(第一個代碼變體),那么你需要將更多的這個邏輯放在getTokenExpiryAsync中。 (順便說一句,這個代碼,如你所示,是同步的,一個代碼路徑返回一個新的Date而另一個返回undefined,所以它不是你想要的。)

現在因為令牌本身是一個承諾,這個getTokenExpiryAsync本身需要異步,因此需要返回到期的承諾。 這是你寫的:

function getTokenExpiryAsync (token) { //I'd pass token as an argument here
    return token.then(
        function complete(result) {
            return result; //Or parse the date from the original response.
        },
        function error(e) {
            return new Date(); 
        }
    );
}

然后在您的調用代碼中,您需要說:

getTokenExpiryAsync(token).then(function (expiry) {
    lastTokenTime = expiry;
}

我們再次利用返回值作為另一個承諾,其履行價值是從已完成或錯誤方法返回的。 如果令牌處於錯誤狀態(WinJS.xhr失敗),那么對.then的調用將調用錯誤處理程序,然后返回所需的默認值。 否則,您將從響應中返回所需的任何到期日期。 無論哪種方式,您都可以在原始調用代碼中從.then獲取此承諾的日期。

我知道這可能有點令人困惑,但它是Promises / A規范和異步編碼的本質,特別是WinJS。

希望這一切都值得您的賞金。 :)

看起來你的函數沒有被調用,因為你沒有調用你的promise函數的完整回調。 此外,你的WinJS.xhr是一個承諾,所以你可以返回它而不包裝在另一個承諾。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM