博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jQuery Deferred
阅读量:7168 次
发布时间:2019-06-29

本文共 3850 字,大约阅读时间需要 12 分钟。

前言

Deferred是从1.5版本引入的一个核心特性之一,主要是为了解决Callback Hell,老生常谈的问题,这里就不多赘述了。本文旨在剖析Deferred的内部实现,让大家能够深入了解Deferred。

API

$.Deferred

通过调用$.Deferred()获取到一个Deferred实例,如下

var dd = $.Deferred();

调用的时候可以传入一个函数(可以简单的看作构造函数),如下

var dd = $.Deferred(function (newDefer) {    newDefer.name = 'My Deferred';});console.log(dd.name);//My Deferred

resolve/done reject/fail notify/progress

Deferred的实现使用了闭包,内部维护了三个$.Callbacks管理队列。

图片描述
可以说Deferred的核心在于$.Callbacks。如果不熟悉$.Callbacks的请自行搜索或参考我的另一篇介绍文章。代码可以简化成下面的样子

var resolveCb = jQuery.Callbacks("once memory");var rejectCb = jQuery.Callbacks("once memory");var notifyCb = jQuery.Callbacks("memory");done        = resolveCb.addresolve     ~ resolveCb.fireresolveWith = resolveCb.fireWithfail        = rejectCb.addreject      ~ rejectCb.firerejectWith  = rejectCb.fireWithprogress    = notifyCb.addnotify      ~ notifyCb.firenotifyWith  = notifyCb.fireWith

~表示可以简单理解为对等。我们再看看下面的代码会不会有不一样的感觉了

var dd = $.Deferred();dd.done(function (name) {    console.log(name, 1);}).done(function (name) {    console.log(name, 2);});dd.resolve('Jacky');

其实就相当于

resolveCb.add(function (name) {    console.log(name, 1);}).add(function (name) {    console.log(name, 2);});resolveCb.fire('Jacky');
  • 当Deferred执行完resolve以后,同时会调用rejectCb.disable和notifyCb.lock。

  • 当Deferred执行完reject以后,同时会调用resolveCb.disable和notifyCb.lock。

  • notifyCb就是一个单纯的$.Callbacks,但是它的状态会受到resolve/reject的影响。

resolveCb和rejectCb两者之间是相互限制的,一旦两者中的某一个fire了,另一个就会被disable。通过这种方式来达到唯一状态。

resolve/resolveWith reject/rejectWith notify/notifyWith

就是fire和firewith的区别

state

返回Deferred的当前状态,总共有三种状态

  • 执行resolve/reject前,返回值是pending

  • 执行了resolve,返回值是resolved

  • 执行了reject,返回值是rejected

    var dd = $.Deferred();

    console.log(dd.state());//pending
    dd.resolve();
    console.log(dd.state());//resolved
    //dd.reject();
    //console.log(dd.state());//rejected

always

看下源码大家就一清二楚了

图片描述
还是调用的done和fail,往各自队列里添加回调。

promise

图片描述

提供Deferred的非状态接口。比较下Deferred和Deferred.promise()

var dd = $.Deferred();var promise = dd.promise();console.log(dd);console.log(promise);

图片描述

也就是说promise返回值是Deferred的一个非状态操作的子集,允许我们添加回调,但是不允许我们操作Deferred的状态。也可以将这些方法添加到某一个对象上,例如

var obj = {name: 'xxx'};var dd = $.Deferred();var newObj = dd.promise(obj);console.log(newObj);console.log(newObj === obj);

图片描述

then/pipe

pipe是为了向下兼容留下的方法,pipe===then。then支持三个参数,返回值是一个新的promise对象。看几个例子

例子一

var dd = $.Deferred();dd.done(function (name) {    console.log('dd', name);});dd.then(function (name) {    console.log('then', name);});dd.resolve('Jacky');//dd Jacky//then Jacky

例子二

var dd = $.Deferred();dd.fail(function (name) {    console.log('dd', name);});dd.then(null, function (name) {    console.log('then', name);});dd.reject('Jacky');//dd Jacky//then Jacky

例子三

var dd = $.Deferred();dd.progress(function (name) {    console.log('dd', name);});dd.then(null, null, function (name) {    console.log('then', name);});dd.notify('Jacky');//dd Jacky//then Jacky

三个参数刚好分别添加到了内部的三个回调队列中。dd.then(fn)可以简单看作dd.done(fn)。前面说了then的返回值是一个新的promise对象,如果在新的Deferred对象上继续添加回调会怎么样呢?我们分两种情况来看。

then方法的返回值不是Deferred对象

var dd = $.Deferred();var newdd = dd.then(function (name) {    console.log('then', name);    return 'Mary';});newdd.done(function (name) {    console.log('newDefer', name);});dd.resolve('Jacky');//then Jacky//newDefer Mary

then的返回值会传递给done/fail的参数。而且无需我们手动调用newdd.resolve,内部帮我们调用了

返回值是Deferred对象

看个例子

var dd = $.Deferred();var returndd = $.Deferred();
var newdd = dd.then(function (name) {    console.log('then', name);    return returndd;});newdd.done(function (name) {    console.log('newDefer', name);});dd.resolve('Jacky');//then Jacky

newdd.done添加的函数没有马上执行了。我们手动调用下returndd.resolve

var dd = $.Deferred();var returndd = $.Deferred();
var newdd = dd.then(function (name) {    console.log('then', name);    return returndd;});newdd.done(function (name) {    console.log('newDefer', name);});dd.resolve('Jacky');//then Jackyreturndd.resolve('Helen');//newDefer Helen

这里就是我们的promise编程了

转载地址:http://fmtwm.baihongyu.com/

你可能感兴趣的文章
WEB测试资料
查看>>
浅谈C#托管程序中的资源释放问题
查看>>
关于用VS实现开机自启动功能(win7/winXp)
查看>>
zz装完UBUNTU后要干的事
查看>>
Linux IPC实践(5) --System V消息队列(2)
查看>>
设置电脑间指定用户共享
查看>>
一种测试方向的探讨-基于模型测试调研引发的思考 - 3
查看>>
tinyPng Photoshop Plugin 安装的坑
查看>>
自动生成卡密SQL脚本(转载)
查看>>
【Android 开发入门】Android设备监视器之调试工具DDMS使用初探
查看>>
JS控制光标定位,定位到文本的某个位置
查看>>
2016年IoT和新的逃逸技术引领威胁态势
查看>>
《敏捷软件开发:原则、模式与实践(C#版.修订版)》—第1章1.2节 原则
查看>>
PHP7扩展开发之类型处理
查看>>
git教程(三)--创建项目并提交更新
查看>>
【推荐】可视化代码评审工具 Phabricator - 我看过的PHP开源框架
查看>>
jQuery.extend 函数详解
查看>>
磁盘管理
查看>>
我的友情链接
查看>>
css3 云朵飘动效果动画
查看>>