【问题标题】:Returning a Javascript Promise from $.ajax call从 $.ajax 调用返回一个 Javascript Promise
【发布时间】:2017-11-04 06:47:18
【问题描述】:

我正在尝试将 $.ajax() 语句转换为 es6 Promise 并返回 es6 Promise。这个想法是我将有一个对 Microsoft Dynamics Web API 的 Create、Update、Delete 调用的应用程序层,它返回一个 es6 Promise,以便我可以在多个页面上重用 Create、Update、Delete 调用。我已经阅读了 GoogleMDNDavid Walsh Blog 关于 es6 Promises 的文章以及几个 SO 问题,但我还没有能够将细节放在一起。

在下面的代码中,当ExpenseUpload.js 调用expenseTransactionSetAPI.Create(newExpenseTransactionSet).then(...)); 时,我看到执行到达then(),但then() 内部没有任何内容正在执行。我不太确定需要进行哪些更改才能使我的代码执行实际处理then(),我什至不确定我是否正确使用了 es6 Promises。任何指导将不胜感激。

ExpenseUpload.js

"use strict";

requirejs.config({
    bundles: {
        'CCSEQ.WebAPI.js': ['Model/ExpenseTransaction', 'Model/ExpenseTransactionSet', 'API/ExpenseTransaction', 'API/ExpenseTransactionSet']
    }
});

require(["Model/ExpenseTransaction", "Model/ExpenseTransactionSet", "API/ExpenseTransaction", "API/ExpenseTransactionSet"], function (ExpenseTransactionModel, ExpenseTransactionSetModel, ExpenseTransactionAPI, ExpenseTransactionSetAPI) {

let file;

$(document).ready(() => {
    setupHandlers();
});

function setupHandlers() {
    $("#csv-file").change((e) => {
        file =  e.target.files[0];
    });

    $("#btnUploadFile").click(() => loadFile());
}

function loadFile() {
    Papa.parse(file, {
        complete: (results) => {
            ImportExpenseTransaction(results.data);
            console.log("import complete");
        }
    });
}

function ImportExpenseTransaction(data) {
    let newExpenseTransactionSet = new ExpenseTransactionSetModel.ExpenseTransactionSet();
    newExpenseTransactionSet.SetName = $("#UploadName").val();
    newExpenseTransactionSet.Month = $("#UploadMonth").val();
    newExpenseTransactionSet.Year = $("#UploadYear").val();
    newExpenseTransactionSet.ImportDate = new Date();
    newExpenseTransactionSet.Status = 100000000;        

    let newExpenseTransactions = new Array();
    data.forEach((expense) => {
        if (expense[0] !== "PR EMP ID") {
            let newRecord = new ExpenseTransactionModel.ExpenseTransaction();
            newRecord. = expense[n];  
            ... // Load other records like above
            newExpenseTransactions.push(newRecord);
        }
    });

    let expenseTransactionSetAPI = new ExpenseTransactionSetAPI.ExpenseTransactionSet();
    let expenseTransactionAPI = new ExpenseTransactionAPI.ExpenseTransaction();
    expenseTransactionSetAPI.Create(newExpenseTransactionSet).
        then((data) => {
            console.log(data);
            console.log("Transaction Set Created");
            expenseTransactionAPI.
                Create(newExpenseTransactions[0]).
                then(() => {
                    console.log("Transaction Created");
                }).catch(() => {
                    console.log("failure");
                });
        }).catch(() => {
            (data) => {
                console.log(data);
                console.log("failure");
            }
        });        
}
});

CCSEQ.WebAPI.js

define("API/ExpenseTransaction", ["require", "exports", "API/APIBase", "Model/ExpenseTransaction"], function (require, exports, APIBase_1, Model) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    class ExpenseTransaction extends APIBase_1.APIBase {
        constructor() {
            super();
            this.ConvertToEntity = (data) => {
                let result = new Array();
                for (let i = 0; i < data.length; i++) {
                    let newRecord = new Model.ExpenseTransaction();
                    newRecord.[field] = data[i]["fieldName"];
                    .
                    .
                    .
                    result[i] = newRecord;
                }
                return result;
            };
        }
        Create(expense) {
            return new Promise((resolve, reject) => {
                $.ajax({
                    url: this.ExpenseTransaction,
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    data: JSON.stringify(expense.toJSON()),
                    success: (data) => { resolve(data); },
                    error: (data) => { reject(data); }
                });
            });
        }
        ;
    }
    exports.ExpenseTransaction = ExpenseTransaction;
});
define("API/ExpenseTransactionSet", ["require", "exports", "API/APIBase", "Model/ExpenseTransactionSet"], function (require, exports, APIBase_2, Model) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    class ExpenseTransactionSet extends APIBase_2.APIBase {
        constructor() {
            super();
            this.ConvertToEntity = (data) => {
                let result = new Array();
                for (let i = 0; i < data.length; i++) {
                    let newRecord = new Model.ExpenseTransactionSet();
                    newRecord.[field] = data[i]["fieldName"];
                    .
                    .
                    .
                    result[i] = newRecord;
                }
                return result;
            };
        }
        Create(expenseSet) {
            return new Promise((resolve, reject) => {
                $.ajax({
                    url: this.ExpenseTransactionSet,
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    data: JSON.stringify(expenseSet.toJSON()),
                    success: (data) => {
                        resolve(data);
                    },
                    error: (data) => {
                        reject(data);
                    }
                });
            });
        }
        ;
    }
    exports.ExpenseTransactionSet = ExpenseTransactionSet;
});
//# sourceMappingURL=CCSEQ.WebAPI.js.map

【问题讨论】:

  • 您看到哪个 .then() 没有被执行?对同一个函数有几个不同的调用
  • @netpoetica 这两个then()s 是微妙的不同。一个来自expenseTransactionSetAPI.Create(),一个来自expenseTransactionAPI.Create()。注意两个调用之一中API() 前面的Set()。我看到第一个then() 的问题来自expenseTransactionSetAPI.Create()
  • FWIW,我整理了一个 jsbin,展示了这一点。我看不出您将 AJAX 调用包装在 promise 中的方法有任何问题 - 它似乎执行正确:jsbin.com/besexatone/edit?html,js,console 我怀疑其他地方的另一个异步进程可能会引发错误,导致您的 .then( ) 也许?

标签: javascript jquery ajax promise es6-promise


【解决方案1】:

只要返回 ajax 请求,它就会返回一个类似 Promise 的对象。

从 jQuery 1.5 开始,由 $.ajax() 返回的 jqXHR 对象实现了 Promise 接口,给他们所有的属性、方法和 Promise 的行为

Create(expense) {
       return $.ajax({
            url: this.ExpenseTransactionSet,
            type: "POST",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            data: JSON.stringify(expenseSet.toJSON())
        });
}

【讨论】:

  • 根据this,这将返回一个jQuery deferred,这可能会导致问题,因为deferred 不遵循Promises/A+ 规范。我不想得到一个实际的 es6 Promises/A+ 兼容的 Promise
  • 我发现 this 的帖子表明,从 jquery 3.0 开始,延迟现在符合 Promises/A+。我会试试这个解决方案。
  • 请注意,Promise.resolve( thenableObject) 是将 thenable 转换为由 Promise 构造函数构造的 ES6 Promise 的标准方法。可以依赖返回的 Promise 以符合标准的行为,例如异步运行 Promise 响应回调并且不使用 thenable 对象来履行 Promise。
猜你喜欢
  • 2013-10-04
  • 2014-10-21
  • 2019-11-26
  • 1970-01-01
  • 2016-03-11
  • 2018-02-24
  • 2012-03-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多