promise 基础学习 (3)

Promise的本质是维护状态,侦测状态,根据状态进行响应。而callback 则是将自身作为参数传入到另一个方法中,作为别的方法体的一部分去调用,因此 Promsie要比 Callback灵活的很多。
如果用代码来做对比的话,promise是这样的:

Promise.resove(2).then(function(v){return v}).then(function(v){return v})

而 callback的方式则是这样的:

doAsync1(function () { doAsync2(function () { doAsync3(function () { doAsync4(function () { }) }) })

总的来说,Promsie的优势更体现与链式调用,而callback(相比较Promise的劣势)就体现在嵌套使用

$.Deferred

对于 Promsie 的实现,Jquery有着自己的一套实现方式,那就是JQ的 $.Deferred 方法。
通过调用 $.Deferred 我们可以获得一个JQ版的异步对象实例。

简单实例:

var def = $.Deferred(); //获得一个JQ的异步对象实例。 def.resolve('success').then(function(v){console.log(v)}); // success

是不是与ES6的 promise 完全一样?如果你真的这样认为那就错了,继续看下面的示例:

var def = $.Deferred(); def.then(function(v){console.log(v)}); def.resolve('success');

是不是发现了一个很大的不同之处,异步对像实例 def 竟然可以通过resolve() 方法自己修改自己的状态!而ES6中的Promsie标准规定的是异步对象的状态不能手动改变,虽然两者不同,但是也无需大惊小怪,毕竟JQ的 $.Deferred 有着自己的实现标准。而且,JQ也提供了另一种受限的异步对象,这个受限的异步对象,基本上就与ES6的 Promise基本一致了。

但是这个受限的异步对象必须要配合一定的写法,才能避免被手动更改状态。

function getAsync() { var def = $.Deferred(); setTimeout(function() { def.resolve('success'); }, 1000); return def.promise(); //返回一个受限制的异步对象实例。 } var dep = getAsync(); dep.then(function(v) { console.log(v); return v }).then(function(v) { console.log(v); return v });

我们可以通过比较受限与不受限的两种异步对象实例,从而更直观的了解这这两者的区别:

console.log($.Deferred()); console.log($.Deferred().promise());

通过打印这两种异步对象,我们明显可以看到受限的对象其含有的方法要远远少于没有受限的实例对象,而其中最明显的就是受限的实例对象并不具有 resolve 方法,这也就直接的说明了受限的异步对象是无法直接修改自己的状态。

由于使用最多的还是受限的异步对象,所以这里我们就大致的说下受限的异步对象具有的一些方法。

then

JQ中异步对象实例的 then 方法与ES6的Promise 对象实例的 then 方法使用格式与功能基本相同,唯一不同的就是JQ对 then 方法的回调处理进行了扩展,加入了 pedding 状态时的回调。

function getAsync() { var def = $.Deferred(); def.notify('loading'); //指定pedding时触发回调,并传入参数。 setTimeout(function() { def.resolve('success'); }, 1000); return def.promise(); //返回一个受限制的异步对象实例。 } var dep = getAsync(); dep.then(function(v) { console.log(v) }, function() {}, function(v) { console.log(v) });

done/fail/progress

done()、fail()、progress() 等方法都是对 then() 方法的功能包装。
done() 表示resolved状态时的处理方法,fail() 表示 rejected 状态时的处理方法,progress() 表示pendding 状态时的处理方法。

function getAsync() { var def = $.Deferred(); def.notify('loading') setTimeout(function() { def.reject('fail'); }, 1000); return def.promise(); //返回一个受限制的异步对象实例。 } var dep = getAsync(); dep.done(function(v){ console.log(v); }); dep.fail(function(v){ console.log(v); }); dep.progress(function(v){ console.log(v); })

always
通过JQ Deferred().promise() 方法返回的受限的异步对象实例中,always 方法类似于 try..catch..finally 中的 finally,不论异步对象的状态是成功还是失败,都会触发该方法。

function getAsync() { var def = $.Deferred(); setTimeout(function() { def.resolve('success'); }, 1000); return def.promise(); //返回一个受限制的异步对象实例。 } var dep = getAsync(); dep.always(function(v){console.log(v)});

state

通过调用 state() 方法可以获得当前对象实例的状态。

$.Deferred().promise().state(); //pending 初探Promise的基本实现

学习一门技术或者是一个工具,最好的办法,莫非于了解它们的大致实现,这里我以自己的方式,编写一个简单的 Promise 对象。
现在只是一个简单的示例,功能还非常简陋只有 then、resolve、reject等功能,而且还有很多bug,但是也足够让我对 promise 有更进一步的认识。

function Deferred(fn) { var _this = this; var doneList = []; // 用于保存 then方法中 resolved状态时的回调函数. var failCallbck = []; // 用于保存 then方法中 rejected状态时的回调函数. this.PromiseValue = undefined; //promsie的值 this.PromiseStatus = 'pending'; //promise的状态 function resolve(v) { //resolve状态的执行函数 setTimeout(function() { //脱离同步代码,以异步的方式执行 then 方法中的代码。 _this.PromiseStatus = 'resolved'; _this.PromiseValue = v; doneList.forEach(function(self, index) { _this.PromiseValue = self(_this.PromiseValue); //保存then方法中回调的return值,以供链式调用时下个then回调函数使用。 }); }, 0); } function reject(v) { //reject状态的执行函数 var idx; //定位failCallbck中最后的失败处理函数的索引。 eg: [1,...,n] 1表示最早最后,n表示最先最近的 setTimeout(function() { //脱离同步代码,以异步的方式执行 then 方法中的代码。 _this.PromiseStatus = 'rejected'; _this.PromiseValue = v; failCallbck.forEach(function(f, i) { if (typeof f != 'undefined' && typeof f == 'function') { idx = i; _this.PromiseValue = f(_this.PromiseValue); return; //对于异常处理函数,只会执行最后的那一个。 } }); _this.PromiseStatus = 'resolved'; //遍历执行doneList中 resolved 状态时的回调函数,但是忽略rejected处理函数之前的所有resolve 状态的回调函数 for (var i = idx + 1; i < doneList.length; i++) { _this.PromiseValue = doneList[i](_this.PromiseValue); } }, 0) } this.then = function(done, faill) { if (this.PromiseStatus === 'pending') { doneList.push(done); failCallbck.push(faill); } else if (this.PromiseStatus === 'resolved') { done(); } else { failCallbck = faill; } return this; } try { fn(resolve, reject); } catch (e) { throw new Error(e); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsgdy.html