jQuery deferred jQuery-1.5 之后的 ajax jQuery promise jQuery deferred 上一节讲到 jquery v1.5 版本开始,$.ajax可以使用类似当前Promise的then函数以及链式操作。那么它到底是如何实现的呢?在此之前所用到的callback在这其中又起到了什么作用?本节给出答案 本节内容概述 写一个传统的异步操作 使用$.Deferred封装 应用then方法 有什么问题? 写一个传统的异步操作 给出一段非常简单的异步操作代码,使用setTimeout函数。 var wait = function () { var task = function () { console.log('执行完成') } setTimeout(task, 2000) } wait() 以上这些代码执行的结果大家应该都比较明确了,即 2s 之后打印出执行完成。但是我如果再加一个需求 ———— 要在执行完成之后进行某些特别复杂的操作,代码可能会很多,而且分好几个步骤 ———— 那该怎么办? 大家思考一下! 如果你不看下面的内容,而且目前还没有Promise的这个思维,那估计你会说:直接在task函数中写就是了!不过相信你看完下面的内容之后,会放弃你现在的想法。 使用$.Deferred封装 好,接下来我们让刚才简单的几行代码变得更加复杂。为何要变得更加复杂?是因为让以后更加复杂的地方变得简单。这里我们使用了 jquery 的$.Deferred,至于这个是个什么鬼,大家先不用关心,只需要知道$.Deferred()会返回一个deferred对象,先看代码,deferred对象的作用我们会面会说。 function waitHandle() { var dtd = $.Deferred() // 创建一个 deferred 对象 var wait = function (dtd) { // 要求传入一个 deferred 对象 var task = function () { console.log('执行完成') dtd.resolve() // 表示异步任务已经完成 } setTimeout(task, 2000) return dtd // 要求返回 deferred 对象 } // 注意,这里一定要有返回值 return wait(dtd) } 以上代码中,又使用一个waitHandle方法对wait方法进行再次的封装。waitHandle内部代码,我们分步骤来分析。跟着我的节奏慢慢来,保证你不会乱。 使用var dtd = $.Deferred()创建deferred对象。通过上一节我们知道,一个deferred对象会有done fail和then方法(不明白的去看上一节) 重新定义wait函数,但是:第一,要传入一个deferred对象(dtd参数);第二,当task函数(即callback)执行完成之后,要执行dtd.resolve()告诉传入的deferred对象,革命已经成功。第三;将这个deferred对象返回。 返回wait(dtd)的执行结果。因为wait函数中返回的是一个deferred对象(dtd参数),因此wait(dtd)返回的就是dtd————如果你感觉这里很乱,没关系,慢慢捋,一行一行看,相信两三分钟就能捋顺! 最后总结一下,waitHandle函数最终return wait(dtd)即最终返回dtd(一个deferred)对象。针对一个deferred对象,它有done fail和then方法(上一节说过),它还有resolve()方法(其实和resolve相对的还有一个reject方法,后面会提到) 应用then方法 接着上面的代码继续写 var w = waitHandle() w.then(function () { console.log('ok 1') }, function () { console.log('err 1') }).then(function () { console.log('ok 2') }, function () { console.log('err 2') }) 上面已经说过,waitHandle函数最终返回一个deferred对象,而deferred对象具有done fail then方法,现在我们正在使用的是then方法。至于then方法的作用,我们上一节已经讲过了,不明白的同学抓紧回去补课。 执行这段代码,我们打印出来以下结果。可以将结果对标以下代码时哪一行。 执行完成 ok 1 ok 2 此时,你再回头想想我刚才说提出的需求(要在执行完成之后进行某些特别复杂的操作,代码可能会很多,而且分好几个步骤),是不是有更好的解决方案了? 有同学肯定发现了,代码中console.log('err 1')和console.log('err 2')什么时候会执行呢 ———— 你自己把waitHandle函数中的dtd.resolve()改成dtd.reject()试一下就知道了。 dtd.resolve() 表示革命已经成功,会触发then中第一个参数(函数)的执行, dtd.reject() 表示革命失败了,会触发then中第二个参数(函数)执行 有什么问题? 总结一下一个deferred对象具有的函数属性,并分为两组: dtd.resolve dtd.reject dtd.then dtd.done dtd.fail 我为何要分成两组 ———— 这两组函数,从设计到执行之后的效果是完全不一样的。第一组是主动触发用来改变状态(成功或者失败),第二组是状态变化之后才会触发的监听函数。 既然是完全不同的两组函数,就应该彻底的分开,否则很容易出现问题。例如,你在刚才执行代码的最后加上这么一行试试。 w.reject() 那么如何解决这一个问题?请听下回分解! jQuery-1.5 之后的 ajax jQuery promise