首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >异步Promise实现

异步Promise实现

作者头像
欲休
发布2018-03-15 13:51:14
9150
发布2018-03-15 13:51:14
举报
文章被收录于专栏:前端杂货铺前端杂货铺

简介 

  异步回调的书写往往打乱了正常流的书写方式,在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                     (function(i){
 37                         args[i].then(function(m){
 38                             ret.push(m);
 39                             if(--counter <= 0){
 40                                 ret.length = len;
 41                                 p.resolve(ret);
 42                             }
 43                         },function(){
 44                             p.reject();
 45                         });
 46                     })(i)
 47                     counter++;
 48                 }
 49                 return p;
 50             };
 51             Promise.prototype = {
 52                 init: function(fn){
 53                     var that = this;
 54                     this.state = 'pending';
 55                     this.callback = {
 56                         onFulfill: Promise.fulfill,
 57                         onReject: Promise.reject
 58                     };
 59                     this.dirty = false;
 60                     this._next = null;
 61                     setTimeout(function(){
 62                         fn && fn.call(that,that.resolve.bind(that),that.reject.bind(that));
 63                     },0)
 64 
 65                 },
 66                 then: function(onFulfill,onReject){
 67                     return post.call(this,onFulfill,onReject);
 68                 },
 69                 wait: function(mills){ //promise链在wait处被分裂成2段
 70                     var p = new Promise(),
 71                             start = new Date().getTime();
 72                     var id = setTimeout(function(){ //传入时间
 73                         p.resolve([this.val,new Date().getTime() - start])
 74                     },mills);
 75                     p.cancel = function(){
 76                         clearTimeout(id);
 77                     }
 78                     return p;
 79                 }
 80             }
 81             function post(onFulfill,onReject,onNotify,onComplete){
 82                 var p = new Promise(),
 83                         that = this;
 84                 if(arguments.length <= 2){
 85                     that._next = p;
 86                     that.callback["onFulfill"] = onFulfill;
 87                     that.callback["onReject"] = onReject;
 88                     this.dirty = true;
 89                 }
 90                 return p;
 91             }
 92             function fire(promise,method){
 93                 var next = "resolve",val,
 94                         args = arguments[2];
 95                 if(promise.state == "pending"){
 96                     try{
 97                         promise.val = val = promise.callback[Promise.map[method]].apply(promise,args);
 98                         promise.state = method;
 99                     }catch(e){
100                         promise.val = val = e;
101                         next = "reject";
102                     }
103 
104                     if(val && isPromise(val)){
105                         val._next = promise._next;
106                     }else{
107                         if(promise._next){
108                             fire(promise._next,next,[val]);
109                         }
110                     }
111 
112                 }
113                 return promise;
114             }
115             function isPromise(o){
116                 return o && typeof o == "object" && o.then && typeof o.then == "function";
117             }
118             "reject,resolve".replace(/\w+/g,function(m){
119                 Promise.prototype[m] = function(){
120                     return fire(this,m,arguments);
121                 }
122             })
123 
124             w.Promise = Promise;
125         })(window)

示例

  示例内容为依次加载网页内容的各个元素:先加载标题,并根据服务器返回的url信息,到相应的文件中加载

内容,并以此显示。

 1       var getJson = function(url){
 2             return new Promise(function(resolve,reject){
 3                 var that = this;
 4                 var xhr = new XMLHttpRequest();
 5                 if(!window.Promise)return;
 6                 xhr.open('get',url);
 7                 xhr.onreadystatechange = function(e){
 8                     if(xhr.readyState == 4){
 9                         if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
10                             resolve(xhr.responseText); log(that)
11                         }else{
12                             reject(new Error('response error'));
13                         }
14                     }
15                 };
16                 xhr.onerror = function(e){
17                     reject(new Error('ajax error'));
18                 }
19                 xhr.send();
20             });
21         };
22 
23         var body = document.body;
24         var addHtml = function(html){
25             if(typeof  html != 'string') return;
26             var p = document.createElement('p');
27             p.textContent = html;
28             body.insertBefore(p,loading);
29         };
30         var addHead = function(html){
31             if(typeof html !== 'string') return;
32             var h = document.createElement('h2');
33             h.textContent = html;
34             body.insertBefore(h,loading);
35         }
36         var log = function(msg){console.log(msg)};
37         var loading = document.getElementById('loading');
38 
39          getJson('../json/head.json').then(JSON.parse).then(function(html){
40             addHead(html.content);
41             Promise.all(html.urls.map(getJson)).then(function(arr){
42                 arr.forEach(function(content){
43                     addHtml(JSON.parse(content).content);
44                 })
45          },function(e){
46                 log('error in loading content: '+ e);
47            })
48          },function(e){
49              log('error: ' + e);
50          }).then(function(){
51             loading.style.display = 'none';
52          })
53 
54         getJson('../json/head.json').then(JSON.parse).then(function(html){
55             addHead(html.content);
56             var promise = Promise.resolve();
57             html.urls.forEach(function(url,i){
58                 promise = promise.then(function(){
59                     return getJson(url);
60                 }).then(JSON.parse).then(function(html){
61                     addHtml(html.content);
62                 },function(e){
63                     log('error in loading body: '+ e );
64                 }).then(function(){
65                     if(i == html.urls.length-1)
66                         loading.style.display = 'none';
67                 })
68             })
69         })

示范

  Promise API控制流程,尤其是对于异步操作而言,流程非常清晰,开飞相对容易。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介 
  • 示例
  • 示范
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档