异步回调的书写往往打乱了正常流的书写方式,在ECMAScript 6中实现了标准的Promise API,旨在
解决控制回调流程的问题。
简单的实现了Promise API:
1 (function(w){ 2 function Promise(fn){ 3 return this instanceof Promise ? this.init(fn) : new Promise(fn); 4 } 5 Promise.fulfill = function(m){return m;}; 6 Promise.reject = function(m){throw m;}; 7 Promise.map = { 8 resolve: "onFulfill", 9 reject: "onReject" 10 } 11 //异步自动生成promise并执行 12 Promise.resolve = function(fn){ 13 var p = new Promise(); 14 setTimeout(function(){ 15 p.resolve(); 16 },0); 17 if(fn) 18 p.callback["onFulfill"] = fn; 19 return p; 20 }; 21 Promise.all = function(){ 22 var p = new Promise(), 23 args; 24 var counter = 0,ret = [];//收集结果,并传给p 25 var v,fn; //传入的函数,执行该函数,将结果保存至ret 26 if(arguments.length > 1){ 27 args = [].slice.apply(arguments) 28 }else if({}.toString.call(arguments[0]) == "[object Array]"){ 29 args = arguments[0]; 30 } 31 for(var i=0,len=args.length;i<len;i++){ 32 if(typeof args[i] == "function"){ 33 args[i] = Promise.resolve(args[i]); 34 35 } 36 37 if(isPromise(args[i])) { //如果为promise对象,则将初始函数值传入数组 38 39 } 40 (function(p,i){ 41 p.then(function(v){ 42 ret.push(v); 43 44 if(--counter <= 0){ 45 ret.length = len; 46 p.resolve(ret); 47 } 48 },function(e){ 49 p.reject(e); 50 }); 51 52 })(args[i],i) 53 counter++; 54 } 55 return p; 56 }; 57 Promise.prototype = { 58 init: function(fn){ 59 var that = this; 60 this.state = ‘pending‘; 61 this.callback = { 62 onFulfill: Promise.fulfill, 63 onReject: Promise.reject 64 }; 65 this.dirty = false; 66 this._next = null; 67 setTimeout(function(){ 68 try{ 69 fn && fn.call(that,that.resolve.bind(that),that.reject.bind(that)); 70 }catch(e){ 71 that.reject(e); 72 } 73 },0) 74 75 }, 76 then: function(onFulfill,onReject){ 77 return post.call(this,onFulfill,onReject); 78 }, 79 wait: function(mills){ //promise链在wait处被分裂成2段 80 var p = new Promise(), 81 start = new Date().getTime(); 82 var id = setTimeout(function(){ //传入时间 83 p.resolve([this.val,new Date().getTime() - start]) 84 },mills); 85 p.cancel = function(){ 86 clearTimeout(id); 87 } 88 return p; 89 } 90 } 91 function post(onFulfill,onReject,onNotify,onComplete){ 92 var p = new Promise(), 93 that = this; 94 if(arguments.length <= 2){ 95 that._next = p; 96 that.callback["onFulfill"] = onFulfill; 97 that.callback["onReject"] = onReject; 98 this.dirty = true; 99 } 100 return p; 101 } 102 function fire(promise,method,args){ 103 var next = "resolve",val; 104 if(promise.state == "pending"){console.log(args) 105 try{ 106 promise.val = val = promise.callback[Promise.map[method]].call(promise,args); 107 promise.state = method; 108 }catch(e){ 109 promise.val = val = e; 110 next = "reject"; 111 } 112 113 if(val && isPromise(val)){ 114 val._next = promise._next; 115 }else{ 116 if(promise._next){ 117 fire(promise._next,next,val); 118 } 119 } 120 121 } 122 return promise; 123 } 124 function isPromise(o){ 125 return o && typeof o == "object" && o.then && typeof o.then == "function"; 126 } 127 "reject,resolve".replace(/\w+/g,function(m){ 128 Promise.prototype[m] = function(args){ 129 return fire(this,m,args); 130 } 131 }) 132 133 w.Promise = Promise; 134 })(window)
简易的demo示范:
1 var getJson = function(url){ 2 return new Promise(function(resolve,reject){ 3 var xhr = new XMLHttpRequest(); 4 if(!window.Promise)return; 5 xhr.open(‘get‘,url); 6 xhr.onreadystatechange = function(e){ 7 if(xhr.readyState == 4){ 8 if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ 9 resolve(xhr.responseText); 10 }else{ 11 reject(new Error(‘response error‘)); 12 } 13 } 14 }; 15 xhr.onerror = function(e){ 16 reject(new Error(‘ajax error‘)); 17 } 18 xhr.send(); 19 }); 20 }; 21 22 var body = document.body; 23 var addHtml = function(html){ 24 if(typeof html != ‘string‘) return; 25 var p = document.createElement(‘p‘); 26 p.textContent = html; 27 body.insertBefore(p,loading); 28 }; 29 var addHead = function(html){ 30 if(typeof html !== ‘string‘) return; 31 var h = document.createElement(‘h2‘); 32 h.textContent = html; 33 body.insertBefore(h,loading); 34 } 35 var log = function(msg){console.log(msg)}; 36 var loading = document.getElementById(‘loading‘); 37 38 /* getJson(‘../json/head.json‘).then(JSON.parse).then(function(html){ 39 addHead(html.content); 40 Promise.all(html.urls.map(getJson)).then(function(arr){ 41 arr.forEach(function(content){ 42 addHtml(JSON.parse(content).content); 43 }) 44 }).catch(function(e){ 45 log(‘error in loading content: ‘+ e); 46 }) 47 }).catch(function(e){ 48 log(‘error: ‘ + e); 49 }).then(function(){ 50 loading.style.display = ‘none‘; 51 })*/ 52 53 getJson(‘../json/head.json‘).then(JSON.parse).then(function(html){ 54 addHead(html.content); 55 var promise = Promise.resolve(); 56 html.urls.forEach(function(url,i){ 57 promise = promise.then(function(){ 58 return getJson(url); 59 }).then(JSON.parse).then(function(html){ 60 addHtml(html.content); 61 }).catch(function(e){ 62 log(‘error in loading body: ‘+ e ); 63 }).then(function(){ 64 if(i == html.urls.length-1) 65 loading.style.display = ‘none‘; 66 }) 67 }) 68 })
时间: 2024-10-13 22:01:35