经由过程 ES6 Promise 和 jQuery Deferred 的异同进修 Promise

Deferred 和 Promise

ES6 和 jQuery 都有 Deffered 和 Promise,然则略有差异。不过它们的作用能够简朴的用两句话来形貌

  • Deffered 触发 resolve 或 reject
  • Promise 中申明 resolve 或 reject 后应当做什么(回调)

在 jQuery 中

var deferred = $.Deferred();
var promise = deferred.promise();

在 ES6 中

var deferred = Promise.defer();
var promise= defered.promise;

MDN 宣告 Deferred 在 Gecko 30 中被申明为逾期,不该当再运用,而应当用 new Promise() 来替代。关于 new Promise() 将在背面申明。

jQuery 的 Deferred/Promise

jQuery 中最经常使用的 Promise 对象是 $.ajax() 返回的,最经常使用的要领不是 then,而是 donefailalways。除了 $.ajax() 外,jQuery 也供应了 $.get()$.post()$.getJSON() 等简化 Ajax 挪用,它们返回的和 $.ajax() 的返回值一样,是个 Promise 对象。

实际上 $.ajax() 返回的是一个 jqXHR 对象。但 jqXHR 完成了 jQuery 的 Promise 接口,所以也是一个 Promise 对象。

done()fail()always()

done() 增加 deferred.resolve() 的回调,fail() 增加 deferred.reject() 的回调。所以在 Ajax 挪用胜利的状况下实行 done() 增加的回调,挪用失利时实行 fail() 增加的回调。但不论胜利与否,都邑实行 always() 增加的回调。

这里 done()fail()always() 都是以类似事宜的体式格局增加回调,也就意味着,不论实行多次次 done()fail()always(),它们增加的多少回调都邑在相符的条件下顺次实行。

平常状况下会如许实行 Ajax

// 禁用按钮以防止反复提交
$("#theButton").prop({
    disabled: true
});

// 挪用 Ajax 提交数据,假定返回的是 JSON 数据
var jqxhr = $.ajax("do/example", {
    type: "post",
    dataType: "json",
    data: getFormData()
});

jqxhr.done(function(jsonObject) {
    // Ajax 挪用胜利
    console.log("success with data", jsonObject);
}).fail(function() {
    // Ajax 挪用失利
    console.log("failed")
}).always(function() {
    // 不论胜利与否,都邑实行,作废按钮的禁用状况
    $("#theButton").prop({
        disabled: false
    });
});

上面是最一般最经常使用的用法,然则在一个项目中老是这么写 Ajax,有点累,轻微商定一下再封装一下就运用起来就会便利很多。起首,假定我们定义返回的 JSON 是如许的花样:

{
    "code": "int, 0 表示胜利,别的值表示失足",
    "message": "string, 附加的音讯,可选",
    "data": "object,附加的数据,可选
}

然后为项目大众类 app 定义一个 ajax 要领

app.ajax = function(button, url, data) {
    if (button) {
        button.prop("disabled", true);
    }

    return $.ajax(url, {
        type: "post",
        dataType: "json",
        data: data
    }).done(function(json) [
        if (json.code !== 0) {
            showError(json.message || "操纵发作毛病");
        }
    }).fail(function() {
        showError("服务器毛病,请稍后再试");
    }).always(function() {
        if (button) {
            button.prop("disabled", false);
        }
    });
};

// 挪用
app.ajax("do/example", getFormData()).done(function(json) {
    if (json.code === 0) {
        // 只须要处置惩罚准确的状况啦
    }
});

不过照样有点不爽,假如不须要推断 json.code === 0 就更好了。这个……能够本身用一个 Deferred 来处置惩罚:

app.ajax = function(button, url, data) {
    if (button) {
        button.prop("disabled", true);
    }

    var deferred = $.Deferred();
    $.ajax(url, {
        type: "post",
        dataType: "json",
        data: data
    }).done(function(json) [
        if (json.code !== 0) {
            showError(json.message || "操纵发作毛病");
            deferred.reject();
        } else {
            deferred.resolve(json);
        }
    }).fail(function() {
        showError("服务器毛病,请稍后再试");
        deferred.reject();
    }).always(function() {
        if (button) {
            button.prop("disabled", false);
        }
    });
    return deferred.promise();
};

// 挪用
app.ajax("do/example", getFormData()).done(function(json) {
    // json.code === 0 老是建立
    // 一般处置惩罚 json.data 就好
});

注重,这里已不是直接返回 $.ajax() 的效果 jqXHR 对象了,返回的是新建 Deferred 对象的 promise 对象。

温习了 Ajax,如今须要切入正题,找到 jQuery Promise 和 ES6 Promise 靠近的处所——then()

jQuery deferred.then()

在 jQuery 1.8 之前(不含 1.8,比方 jQuery 1.7.2),deferred.then() 就是一个把 done()fail() 放在一同的语法糖。jQuery 在 1.8 版本的时刻修改了 deferred.then() 的行动,使 then() 的行动与 Promise 的 then() 类似。从 jQuery 的文档能够看到 1.8 版本的变化——干掉了 callback,换成了 filter:

// version added: 1.5, removed: 1.8
deferred.then( doneCallbacks, failCallbacks )

// version added: 1.7, removed: 1.8
deferred.then( doneCallbacks, failCallbacks [, progressCallbacks ] )

// version added: 1.8
deferred.then( doneFilter [, failFilter ] [, progressFilter ] )

能够简朴的把 callback 看成一个事宜处置惩罚,值用于 callback 以后平常不会转变;而 filter 差异,一个值传入 filter 再从 filter 返回出来,能够已变了。照样举个例子来申明

var deferred = $.Deferred();
var promise = deferred.promise();
promise.then(function(v) {
    console.log(`then with ${v}`);
}).done(function(v) {
    console.log(`done with ${v}`);
});
deferred.resolve("resolveData");

在 jQuery 1.7.2 中的效果

then with resolveData
done with resolveData

在 jQuery 1.8.0 中的效果

then with resolveData
done with undefined

从上面来看,jQuery 的 deferred.then() 语义和 ES6 Promise.then() 语义基础一致。假如把上面的 app.ajax 换成 then() 完成会有助于对 ES6 Promise 的明白。

app.ajax = function(button, url, data) {
    if (button) {
        button.prop("disabled", true);
    }

    return $.ajax(url, {
        type: "post",
        dataType: "json",
        data: data
    }).then(function(json) {
        if (json.code !== 0) {
            showError(json.message || "操纵发作毛病");
            return $.Deferred().reject().promise();
        } else {
            return $.Deferred().resolve(json).promise();
        }
    }, function() {
        showError("服务器毛病,请稍后再试");
        deferred.reject();
    }).always(function() {
        if (button) {
            button.prop("disabled", false);
        }
    });
};

// 挪用体式格局没变,用 done,也能够用 then
app.ajax("do/example", getFormData()).done(function(json) {
    // json.code === 0 老是建立
    // 一般处置惩罚 json.data 就好
});

从 jQuery Promise 到 ES6 Promise

上面的代码太长,提炼一下症结部份(表示,不能运转)

var promise = $.ajax();
promise.then(function(data) {
    // resolve
    return data.code
        ? new Promise().reject()
        : new Promise().resolve(data);
        
    // 假如没有错,就返回一个新的 promise,并运用 data 来 resolve,
    // 也能够直接返回 data,
    // 如许背面 then 的 resolve 部份才收到数据
}, function() {
    // rejected
});

// 挪用阶段
promise.then(function(data) {
    // 处置惩罚 data
});

或许你没注重到,实在上面的代码基础上就是 ES6 的 Promise 了。下面正式用 ES6 Promise 改写上面的表示代码

var promise = new Promise(function(resolve, reject) {
    $.ajax().then(resolve, reject);
    // 上面这句没看懂?那换成如许你一定会懂
    // $.ajax().then(function(data) {
    //     resolve(data);
    // }, function() {
    //     reject();
    // });
}).then(function(data) {
    return data.code
        ? Promise.reject()
        : Promise.resolve(data);

    // 这里 Promise.resolve(data) 一样能够直接替换为 data
});

// 挪用没变
promise.then(function(data) {
    // 处置惩罚 data
});

怎样,差异不大吧。不知不觉就会 ES6 Promise 了!

ES6 的 Promise

上面已把 ES6 的 Promise 带出来了,如今只须要把经常使用要领列出来作为参考即可

注重,小写的 promise 表示 Promise 对象

  • new Promise(executor),发生一个新的 Promise 对象

    > `executor(resolve, reject)`
    > `executor`、`resolve` 和 `reject` 均为函数,在 `executor` 中,准确处置惩罚挪用 `resolve()` 返回数据,非常处置惩罚直接 `throw new Error(...)` 或调 `reject()` 返回数据。
    
  • Promise.resolve(data),发生 Promise 对象并 resolve
  • Promise.reject(),发生 Promise 对象并 reject
  • promise.then(onResolve, onReject),然后……继承处置惩罚
  • promise.catch(onReject)project.then(null, onReject) 的语法糖,和 jQuery 的 promise.fail() 差不多(但差异)。

参考

    原文作者:边城
    原文地址: https://segmentfault.com/a/1190000003691961
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞