在 $.ajax().done() 调用链中,我可以为下一个 .done() 转换数据吗?

In a chain of $.ajax().done() calls, can I transform data for next .done()?

我有一个现有的 api 例程,我想在调用下一个 .done() 之前插入转换。在我的例子中,它需要一个简单的额外级别 JSON.parse() 但更广泛的问题是我可以对下一个 .done() 能够看到的响应数据做任何事情吗?

所以拿这个 api :

function foo(){
   return $.ajax( ... )
           .done(data=> {  .. do something with the data here ...});
}

来电者可以看到:

foo().done(data=>{ .. transformed data visible here ... });

jQuery 的 ajax return 是一个 Deferred 对象,这是(现在)根据 Promises/A+ 规范的承诺。所以你可以切换到使用 then,它具有你正在寻找的语义:

function foo(){
   return $.ajax( ... )
           .then(data => {
               return /*...the transformed data...*/;
           });
}

然后:

foo().then(data => { /*.. transformed data visible here ...*/ });

注意:如果调用foo的代码无法更改,不用担心; done 也会看到更新后的数据。但必须在thenfoo以内。如果可以,也可以在调用 foo 的代码中切换到 then,但如果不能,也没关系。

这是一个在 foodone 中使用 then 的实例:https://jsfiddle.net/tjcrowder/y1zh2xL4/

function foo(){
    return $.ajax({
        method: "POST",
        url: "/echo/json/",
        data: {
            json: '{"key":"value"}',
            delay: 1
        }
    })
    .then(data => {
        return {key: data.key.toUpperCase()};
    });
}

// Just to show that `done` sees the updated data
foo().done(data => { console.log(data); });

在您提出的评论中:

Further question; is there a way to do the same sort of transform in an error chain?

是啊! Promises 的设计使得两条路径可以在每个级别进行转换。要转换通过链的拒绝,您可以 return 一个被拒绝的承诺 (return Promise.reject(x)) 或抛出 (throw x)。 x 可以是任何你想要的,尽管按照惯例它通常是一个 Error 对象。

例如 (https://jsfiddle.net/tjcrowder/y1zh2xL4/1/):

function foo(){
    return $.ajax({
        method: "POST",
        url: "/echo/bad-url-not-on-jsfiddle",
        data: {
            json: '{"key":"value"}',
            delay: 1
        }
    })
    .then(data => {
        return {key: data.key.toUpperCase()};
    })
    .catch(error => {
        const myError = new Error("ajax failed");
        myError.originalError = error;
        myError.otherInformation = "whatever";
        throw myError;
    });
}

foo()
.done(data => { console.log(data); })
.fail(error => {
    console.error(error);
    console.error(error.otherInformation);
});