异步Promise实现
时间:2022-05-04
本文章向大家介绍异步Promise实现,主要内容包括简介、示例、示范、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。
简介
异步回调的书写往往打乱了正常流的书写方式,在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控制流程,尤其是对于异步操作而言,流程非常清晰,开飞相对容易。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Ansible搭建hadoop-3.1.3高可用
- Android | xml和view的那些事
- Android | Glide细枝篇
- 从源代码编译安装 MonoDevelop 记录
- 在 Asp.Net Core WebAPI 中防御跨站请求伪造攻击
- Hash 算法有哪些?
- Cordova 运行 Web 应用
- SSH 端口转发小结
- Hive实现自增序列及元数据问题
- 手工将项目升级至 Angular 9 记录
- 备份和恢复 timescaledb 的超级表 (hypertables)
- CVE-2020-14644 weblogic iiop反序列化漏洞
- Ubuntu 17.10 安装折腾记录
- charles工具使用
- 干货 | 从0到1,搭建一个体系完善的前端React组件库