Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

前端异步技术之Promise

蟹丸 2019-02-24 02:26:00 阅读数:157 评论数:0 点赞数:0 收藏数:0

前言

从事前端的朋友或多或少的接触过Promise,当代码中回调函数层级过多你就会发现Promise异步编程的魅力,相信此文一定能帮你排忧解惑!

Promise概念

Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一或许是笔者理解能力有限,对官方术语怎么也感受不到亲切,下面我来用通俗易懂的语言解释下:Promise是一个包含三种状态的对象(pending、fulfilled、rejected),可以链式的处理异步请求(then方法)并能很好地处理异常问题,是解决回调地狱的良好方案之一。 回调函数处理多层异步示例

$.ajax({ url: url1, success:function(rsp){ $.ajax({ url: url2, success:function(rsp){ $.ajax({ url: url3, success:function(rsp){//do sth }, error:function(error){ } }); }, error:function(error){ } }); }, error:function(error){ } });将promise封装在$.ajax中

$.ajax = function(config){return new Promise(function(resolve, reject){//1省略... xmlhttp.onreadystatechange = function(){if(xmlhttp.status==200){ resolve(rspData); }else{ reject(xmlhttp.statusText); } };//2省略... }) } $.ajax({url: url1}).then(function(val){return$.ajax({url: val.url}) }).then(function(val){return$.ajax({url: val.url}) }).catch(function(err){ console.log(err); }}封装好的Promise处理异步可读性可维护性以及代码美观度不言而喻

Promise API

'new' Promise

//pending状态的promise var promise = new Promise(function(resolve, reject){//do sth })//fulfilled状态的promise var promise = Promise.resolve(1).then(functionresolve(value){console.log(value)});//var promise = new Promise(function(resolve){resolve(1)})//rejected状态的promise var promise = Promise.reject(new Error('error')).catch(function(error){console.error(error)});//var promise = new Promise(function(resolve,reject){resolve(new Error('error'))})

Promise.prototype.then

Promise/#then promise.then(onFulfilled, onRejected) 返回一个新的promise。这里经常会有一个疑问:为什么不返回原来的promise,个人是这样认为的,若返回同一个promise则状态不一致,promise规范说明当pending至fulfilled/rejected时状态确定后不能再改变。

Promise.prototype.catch

Promise/#catchpromise.catch(function(error){throw newError(error); }) 注意:IE8及以下版本会出现 identifier not found 的语法错误,可将点标记法改为中括号标记法

promise'catch'{throw newError(error); })rejected状态的promise抛出异常相当于

promise.then(undefined, onRejected)then & catch 结合示例

promise.then(functionf1(value){//do sth 1 }).then(functionf2(value){//do sth 2 }).then(functionf3(value){//do sth 3 }).catch(function(error){ console.log(error); })

Promise.prototype.finally

promise.finally(onFinally) 返回一个Promise,在promise执行结束时,无论结果是fulfilled或者是rejected,在执行then()和catch()后,都会执行

Promise.all

promise.all([promise1, promise2, promise3]).then(resolve); 示例

//delay毫秒后执行resolve functiontimerPromisefy(delay) {return new Promise(function(resolve) { setTimeout(function() { resolve(delay); }, delay); }); }var startDate =Date.now();//所有promise变为resolve后程序退出 Promise.all([ timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128) ]).then(function(values) { console.log(Date.now()- startDate + 'ms');//约128ms console.log(values); //[1,32,64,128] });在接收到所有的对象promise都变为 FulFilled 返回一个resolve(array),或者 某一个promise对象变成Rejected 状态返回resolve(err)传递给 Promise.all 的promise并不是一个个的顺序执行的,而是同时开始、并行执行的。

Promise.race

promise.race([promise1, promise2]).then(resolve, reject) 示例

//delay毫秒后执行resolve functiontimerPromisefy(delay) {return new Promise(function(resolve) { setTimeout(function() { resolve(delay); }, delay); }); }//任何一个promise变为resolve或reject 的话程序就停止运行 Promise.race([ timerPromisefy(1), timerPromisefy(32), timerPromisefy(64), timerPromisefy(128) ]).then(function(value) { console.log(value);//=> 1 });只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。

Promise polyfill & Test

promise-polyfill.js

学习完Promise后,必定要重写Promise,后续遇到浏览器环境不支持也可有的放矢代码如下

/// / @author chenchangyuan / @date 2019-02-23 /// functionPromise(executor){if(typeof executor !== 'function'){throw new Error('executor is not a function'); }var self = this; self.state= 'pending';//pending fulfilled rejected self.value = null; self.reason= null; self.callbackResolveFn=[]; self.callbackRejectFn=[];functionresolve(value){if(self.state === 'pending'){ self.state= 'fulfilled'; self.value=value; self.callbackResolveFn.forEach(function(fn){ fn(); }); } }functionreject(reason){if(self.state === 'pending'){ self.state= 'rejected'; self.reason=reason; self.callbackRejectFn.forEach(function(fn){ fn(); }); } }try{ executor(resolve, reject); }catch(err){ reject(err); } }//回溯函数 functionresolvePromise(promise, x, resolve, reject){if(promise === x) return reject(new TypeError('循环引用'));var flag = false;if(x !== null && (typeof x === 'object' || typeof x === 'function')){try{var then =x.then;if(typeof then === 'function'){ then.call(x,function(val){if(flag) return; flag= true; resolvePromise(promise, val, resolve, reject); },function(err){if(flag) return; flag= true; reject(err); }); }else{ resolve(x); } }catch(err){if(flag) return; flag= true; reject(err); } }else{ resolve(x); } }//返回一个新的promise(pending:push(fn),fulfilled:resolve(val),rejected:reject(reason)) Promise.prototype.then = function(onFulfilled, onRejected){ onFulfilled= typeof onFulfilled === 'function' ? onFulfilled : function(value){returnvalue; }; onRejected= typeof onRejected === 'function' ? onRejected : function(err){throw newError(err); };var self = this, promise2;if(self.state === 'fulfilled'){ promise2= new Promise(function(resolve, reject){ setTimeout(function(){try{//将x处理成一个原始值 var x =onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); }catch(e){ reject(e); } }) }) }if(self.state === 'rejected'){ promise2= new Promise(function(resolve, reject){ setTimeout(function(){try{//将x处理成一个原始值 var x =onRejected(self.reason); resolvePromise(promise2, x, resolve, reject); }catch(e){ reject(e); } }) }) }if(self.state === 'pending'){ promise2= new Promise(function(resolve, reject){ self.callbackResolveFn.push(function(){ setTimeout(function(){try{//将x处理成一个原始值 var x =onFulfilled(self.value); resolvePromise(promise2, x, resolve, reject); }catch(e){ reject(e); } }) }); self.callbackRejectFn.push(function(){ setTimeout(function(){try{//将x处理成一个原始值 var x =onRejected(self.reason); resolvePromise(promise2, x, resolve, reject); }catch(e){ reject(e); } }) }); }) }returnpromise2; } Promise.prototype['catch']= function(callback) {return this.then(undefined, callback) } Promise.all= function(promises) {return new Promise(function(resolve, reject) { let arr=[]; let i= 0;functionprocessData(index, y) { arr[index]=y;if (++i ===promises.length) { resolve(arr); } }for (let i = 0; i < promises.length; i++) { promises[i].then(function(y) { processData(i, y) }, reject) } }) } Promise.race= function(promises) {return new Promise(function(resolve, reject) {for (var i = 0; i < promises.length; i++) { promises[i].then(resolve,reject) } }); } Promise.resolve= function(value){return new Promise(function(resolve,reject){ resolve(value); }); } Promise.reject= function(reason){return new Promise(function(resolve,reject){ reject(reason); }); } Promise.defer= Promise.deferred = function() {var d ={}; d.promise= new Promise(function(resolve, reject) { d.resolve=resolve; d.reject=reject; });returnd } module.exports= Promise;

promise-aplus-tests

由于是参(抄)考(袭)前辈的polyfill,自己编码测试时出现了两处错误,ES6 Promise 规范的2.3.1和2.3.4

2.3.1

2.3.4

经过改正测试成功

后记

你们的支持是我最大的动力,熬夜码字不易,如果此文对你有帮助,请不吝star--->https://github.com/chenchangyuan/promise

有兴趣加笔者好友的同学请扫描下方二维码(1.本人微信,2.微信公众号,3.技术交流微信群),愿与您成为好友共同探讨技术,畅聊生活!

 

参考资料

https://promisesaplus.com/

http://liubin.org/promises-book

https://juejin.im/post/5ab20c58f265da23a228fe0f

版权声明
本文为[蟹丸]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/ccylovehs/p/10425199.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领