异步Promise实现
简介
异步回调的书写往往打乱了正常流的书写方式,在ECMAScript 6中实现了标准的Promise API,旨在
解决控制回调流程的问题。
简单的实现了Promise API:
(function(w){
function Promise(fn){
return this instanceof Promise ? this.init(fn) : new Promise(fn);
}
Promise.fulfill = function(m){return m;};
Promise.reject = function(m){throw m;};
Promise.map = {
resolve: "onFulfill",
reject: "onReject"
}
//异步自动生成promise并执行
Promise.resolve = function(fn){
var p = new Promise();
setTimeout(function(){
p.resolve();
},0);
if(fn)
p.callback["onFulfill"] = fn;
return p;
};
Promise.all = function(){
var p = new Promise(),
args;
var counter = 0,ret = [];//收集结果,并传给p
var v,fn; //传入的函数,执行该函数,将结果保存至ret
if(arguments.length > 1){
args = [].slice.apply(arguments)
}else if({}.toString.call(arguments[0]) == "[object Array]"){
args = arguments[0];
}
for(var i=0,len=args.length;i<len;i++){
if(typeof args[i] == "function"){
args[i] = Promise.resolve(args[i]);
}
(function(i){
args[i].then(function(m){
ret.push(m);
if(--counter <= 0){
ret.length = len;
p.resolve(ret);
}
},function(){
p.reject();
});
})(i)
counter++;
}
return p;
};
Promise.prototype = {
init: function(fn){
var that = this;
this.state = 'pending';
this.callback = {
onFulfill: Promise.fulfill,
onReject: Promise.reject
};
this.dirty = false;
this._next = null;
setTimeout(function(){
fn && fn.call(that,that.resolve.bind(that),that.reject.bind(that));
},0)
},
then: function(onFulfill,onReject){
return post.call(this,onFulfill,onReject);
},
wait: function(mills){ //promise链在wait处被分裂成2段
var p = new Promise(),
start = new Date().getTime();
var id = setTimeout(function(){ //传入时间
p.resolve([this.val,new Date().getTime() - start])
},mills);
p.cancel = function(){
clearTimeout(id);
}
return p;
}
}
function post(onFulfill,onReject,onNotify,onComplete){
var p = new Promise(),
that = this;
if(arguments.length <= 2){
that._next = p;
that.callback["onFulfill"] = onFulfill;
that.callback["onReject"] = onReject;
this.dirty = true;
}
return p;
}
function fire(promise,method){
var next = "resolve",val,
args = arguments[2];
if(promise.state == "pending"){
try{
promise.val = val = promise.callback[Promise.map[method]].apply(promise,args);
promise.state = method;
}catch(e){
promise.val = val = e;
next = "reject";
}
if(val && isPromise(val)){
val._next = promise._next;
}else{
if(promise._next){
fire(promise._next,next,[val]);
}
}
}
return promise;
}
function isPromise(o){
return o && typeof o == "object" && o.then && typeof o.then == "function";
}
"reject,resolve".replace(/\w+/g,function(m){
Promise.prototype[m] = function(){
return fire(this,m,arguments);
}
})
w.Promise = Promise;
})(window)
示例
示例内容为依次加载网页内容的各个元素:先加载标题,并根据服务器返回的url信息,到相应的文件中加载
内容,并以此显示。
var getJson = function(url){
return new Promise(function(resolve,reject){
var that = this;
var xhr = new XMLHttpRequest();
if(!window.Promise)return;
xhr.open('get',url);
xhr.onreadystatechange = function(e){
if(xhr.readyState == 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
resolve(xhr.responseText); log(that)
}else{
reject(new Error('response error'));
}
}
};
xhr.onerror = function(e){
reject(new Error('ajax error'));
}
xhr.send();
});
};
var body = document.body;
var addHtml = function(html){
if(typeof html != 'string') return;
var p = document.createElement('p');
p.textContent = html;
body.insertBefore(p,loading);
};
var addHead = function(html){
if(typeof html !== 'string') return;
var h = document.createElement('h2');
h.textContent = html;
body.insertBefore(h,loading);
}
var log = function(msg){console.log(msg)};
var loading = document.getElementById('loading');
getJson('../json/head.json').then(JSON.parse).then(function(html){
addHead(html.content);
Promise.all(html.urls.map(getJson)).then(function(arr){
arr.forEach(function(content){
addHtml(JSON.parse(content).content);
})
},function(e){
log('error in loading content: '+ e);
})
},function(e){
log('error: ' + e);
}).then(function(){
loading.style.display = 'none';
})
getJson('../json/head.json').then(JSON.parse).then(function(html){
addHead(html.content);
var promise = Promise.resolve();
html.urls.forEach(function(url,i){
promise = promise.then(function(){
return getJson(url);
}).then(JSON.parse).then(function(html){
addHtml(html.content);
},function(e){
log('error in loading body: '+ e );
}).then(function(){
if(i == html.urls.length-1)
loading.style.display = 'none';
})
})
})
示范
Promise API控制流程,尤其是对于异步操作而言,流程非常清晰,开飞相对容易。
异步Promise实现的更多相关文章
- 异步Promise及Async/Await可能最完整入门攻略
此文只介绍Async/Await与Promise基础知识与实际用到注意的问题,将通过很多代码实例进行说明,两个实例代码是setDelay和setDelaySecond. tips:本文系原创转自我的博 ...
- 异步Promise及Async/Await最完整入门攻略
一.为什么有Async/Await? 我们都知道已经有了Promise的解决方案了,为什么还要ES7提出新的Async/Await标准呢? 答案其实也显而易见:Promise虽然跳出了异步嵌套的怪圈, ...
- 异步-promise、async、await
下面代码打印结果是? setTimeout(()=>{ console.log(1) }) new Promise((resolve,reject)=>{ console.log(2) r ...
- Promise与异步
不知道promise,大家现在用了吗?如果还不了解的话,今天就来对了-基础的了解起来- 正文从这开始- 接触过promise的的都知道它的应用场景和用途,Promise可以用来避免异步操作函数里的嵌套 ...
- promise 的基本概念 和如何解决js中的异步编程问题 对 promis 的 then all ctch 的分析 和 await async 的理解
* promise承诺 * 解决js中异步编程的问题 * * 异步-同步 * 阻塞-无阻塞 * * 同步和异步的区别? 异步;同步 指的是被请求者 解析:被请求者(该事情的处理者)在处理完事情的时候的 ...
- javascript基础修炼(7)——Promise,异步,可靠性
开发者的javascript造诣取决于对[动态]和[异步]这两个词的理解水平. 一. 别人是开发者,你也是 Promise技术是[javascript异步编程]这个话题中非常重要的,它一度让我感到熟悉 ...
- Promise、async、await 异步解决方案
参考: https://www.cnblogs.com/CandyManPing/p/9384104.html 或 https://www.jianshu.com/p/fe0159f8beb4(推 ...
- 异步编程之Generator(1)——领略魅力
异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...
- 4、promise
es5 中 var obj = { ajax: function (callback) { console.log('执行') setTimeout(function () { callback &a ...
随机推荐
- Django 搭建简易博客
新增一个 APP 博客算是一个功能集,因此我们应将其体现为一个模块.这表现在 Django 应用里则是为其创建一个 APP Package.现在让 manage.py 中的 startapp 闪亮登场 ...
- 方维 o2o app源码出售
方维 o2o app源码出售 方维o2oapp源码出售 1.本人官方5万购买,现把方维o2o app 源码低价出售: 2.包括网站源码本地搭建包成功提供指导 3.包括网站说明文档,不包含app说明文档 ...
- 报文解析及CRC类
/// <summary> /// 报文解析转换类 /// </summary> public class DatagramConvert { public static En ...
- 看看Maple T.A.的详细作用
Maple T.A.是一个基于互联网的在线考试和智能评分系统,是Maplesoft公司 与美国数学协会(MAA)合作开发的成果,在全球拥有大量的院校用户.Maple T.A.提供了用户数据库.所见即所 ...
- matlab size、numel、length、fix函数的使用,补充nargin
size():获取矩阵的行数和列数 (1)s=size(A), 当只有一个输出参数时,返回一个行向量,该行向量的第一个元素时矩阵的行数,第二个元素是矩阵的列数.(2)[r,c]=size(A), 当有 ...
- ABP理论学习之开篇介绍
返回总目录 为了和2016年春节赛跑,完成该系列博客,我牺牲了今天中午的时间来完成该系列的第一篇----开篇介绍.开篇介绍嘛,读过大学教材的同学都知道,这玩意总是那么无聊,跟考试没关系,干脆直接跳过, ...
- 【干货】JS版汉字与拼音互转终极方案,附简单的JS拼音输入法
前言 网上关于JS实现汉字和拼音互转的文章很多,但是比较杂乱,都是互相抄来抄去,而且有的不支持多音字,有的不支持声调,有的字典文件太大,还比如有时候我仅仅是需要获取汉字拼音首字母却要引入200kb的字 ...
- 为jQuery添加Webkit的触摸方法支持
前些日子收到邮件,之前兼职的一个项目被转给了其他人,跟进的人来问我相关代码的版权问题. 我就呵呵了. 这段代码是我在做13年一份兼职的时候无聊加上去的,为jQuery添加触摸事件的支持.因为做得有点无 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (40) ------ 第七章 使用对象服务之从跟踪器中获取实体与从命令行生成模型(想解决EF第一次查询慢的,请阅读)
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 7-5 从跟踪器中获取实体 问题 你想创建一个扩展方法,从跟踪器中获取实体,用于数 ...
- iOS-常见问题
11.21常见问题 一storyboard连线问题 产生原因:将与storyboard关联的属性删除了,但是storyboard中还保持之前所关联的属性. 解决: 点击view controller ...