建站资讯
2017-08-23 18:16:21
浏览:
$.ajax
$.ajax
Promise
的关系$.ajax
先来一段最常见的$.ajax
的代码,当然是使用万恶的callback
方式
var ajax = $.ajax({ url: 'data.json', success: function () { console.log('success') }, error: function () { console.log('error') } }) console.log(ajax) // 返回一个 XHR 对象
至于这么做会产生什么样子的诟病,我想大家应该都很明白了。不明白的自己私下去查,但是你也可以继续往下看,你只需要记住这样做很不好就是了,要不然 jquery 也不会再后面进行改进
$.ajax
但是从v1.5
开始,以上代码就可以这样写了:可以链式的执行done
或者fail
方法
var ajax = $.ajax('data.json') ajax.done(function () { console.log('success 1') }) .fail(function () { console.log('error') }) .done(function () { console.log('success 2') }) console.log(ajax) // 返回一个 deferred 对象
大家注意看以上两段代码中都有一个console.log(ajax)
,但是返回值是完全不一样的。
v1.5
之前,返回的是一个XHR
对象,这个对象不可能有done
或者fail
的方法的v1.5
开始,返回一个deferred
对象,这个对象就带有done
和fail
的方法,并且是等着请求返回之后再去调用
这是一个标志性的改造,不管这个概念是谁最先提出的,它在 jquery 中首先大量使用并让全球开发者都知道原来 ajax 请求还可以这样写。这为以后的Promise
标准制定提供了很大意义的参考,你可以以为这就是后面Promise
的原型。
记住一句话————虽然 JS 是异步执行的语言,但是人的思维是同步的————因此,开发者总是在寻求如何使用逻辑上看似同步的代码来完成 JS 的异步请求。而 jquery 的这一次更新,让开发者在一定程度上得到了这样的好处。
之前无论是什么操作,我都需要一股脑写到callback
中,现在不用了。现在成功了就写到done
中,失败了就写到fail
中,如果成功了有多个步骤的操作,那我就写很多个done
,然后链式连接起来就 OK 了。
Promise
的关系
以上的这段代码,我们还可以这样写。即不用done
和fail
函数,而是用then
函数。then
函数的第一个参数是成功之后执行的函数(即之前的done
),第二个参数是失败之后执行的函数(即之前的fail
)。而且then
函数还可以链式连接。
var ajax = $.ajax('data.json') ajax.then(function () { console.log('success 1') }, function () { console.log('error 1') }) .then(function () { console.log('success 2') }, function () { console.log('error 2') })
如果你对现在 ES6 的Promise
有了解,应该能看出其中的相似之处。不了解也没关系,你只需要知道它已经和Promise
比较接近了。后面马上会去讲Promise
明眼人都知道,jquery 不可能改变异步操作需要callback
的本质,它只不过是自己定义了一些特殊的 API,并对异步操作的callback
进行了封装而已。
那么 jquery 是如何实现这一步的呢?请听下回分解!
上一节讲到 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 的deferred
对象是解决了异步中callback
函数的问题,但是
本节使用的代码参见这里
promise
promise
的好处promise
我们对上一节的的代码做一点小小的改动,只改动了一行,下面注释。
function waitHandle() { var dtd = $.Deferred() var wait = function (dtd) { var task = function () { console.log('执行完成') dtd.resolve() } setTimeout(task, 2000) return dtd.promise() // 注意,这里返回的是 primise 而不是直接返回 deferred 对象 } return wait(dtd) } var w = waitHandle() // 经过上面的改动,w 接收的就是一个 promise 对象 $.when(w) .then(function () { console.log('ok 1') }) .then(function () { console.log('ok 2') })
改动的一行在这里return dtd.promise()
,之前是return dtd
。dtd
是一个deferred
对象,而dtd.promise
就是一个promise
对象。
promise
对象和deferred
对象最重要的区别,记住了————promise
对象相比于deferred
对象,缺少了.resolve
和.reject
这俩函数属性。这么一来,可就完全不一样了。
上一节我们提到一个问题,就是在程序的最后一行加一句w.reject()
会导致乱套,你现在再在最后一行加w.reject()
试试 ———— 保证乱套不了 ———— 而是你的程序不能执行,直接报错。因为,w
是promise
对象,不具备.reject
属性。
promise
的好处waitHandle
函数内部,使用dtd.resolve()
来该表状态,做主动的修改操作waitHandle
最终返回promise
对象,只能去被动监听变化(then
函数),而不能去主动修改操作一个“主动”一个“被动”,完全分开了。
如何通过优化提升手机网站用户体验
随着智能手机的普及和移动互联网的发展,手机网站已成为企业互联网营销的重要渠道之一。然而,由于移动设备的特殊性,手机网站的用户体验常常受到限制。本文将从多个方面为
手机网站制作的关键步骤:从规划到上线
随着移动互联网的快速发展,手机网站成为了企业不可或缺的一部分。拥有一个响应式的手机网站,能够极大地提升用户体验,提高品牌知名度,并且增加转化率。然而,手机网站制作并不是一项简单的任务。本文将逐步介绍手机网站制作的关键步骤,帮助您更好地准备和完成手机网站的建设。
为什么需要手机网站制作?
手机网站制作是为了跟上市场趋势和竞争对手。现在大多数行业都有自己的手机应用或手机网站,如果您的竞争对手已经拥有了手机网站,那么您不制作的话,您将与时俱进的道路就变得更加艰难。通过制作手机网站,您可以提前占领手机市场,赢得更多用户的青睐,并与竞争对手保持一定的竞争力。