异步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 ...
随机推荐
- highchart 添加新的series
code: <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" c ...
- Centos 6.5 搭建l2tp 服务端和客户端
废话不多说直接上步骤. server #epel仓库愿安装 rpm -ivh http://mirrors.ustc.edu.cn/fedora/epel/6/x86_64/epel-release- ...
- min.js反压缩
给个网址自己体会.. http://jsbeautifier.org/ 当需要修改min.js中的代码时,把min.js文件ctrl+c ctrl+v扔到上面的网页里,点击beautify 即可
- 一图搞定【实战Java高并发程序设计】
来了解下java并发的技术点吧.这里面包括了并发级别.算法.定律,还有开发包.在过去单核CPU时代,单任务在一个时间点只能执行单一程序,随着多核CPU的发展,并行程序开发就显得尤为重要.这本书主要介绍 ...
- 使用PowerShell找出具体某个站点所使用的模板(Web Template)名称?
$web = get-spweb –identity http://servername/sites/site/web #得到站点的对象 $web.WebTemplate #得到WebTemplate ...
- C语言中的栈和堆
原文出处<http://blog.csdn.net/xiayufeng520/article/details/45956305#t0> 栈内存由编译器分配和释放,堆内存由程序分配和释放. ...
- Java演算法之快速排序法
1 * 快速排序法(Quick Sort),遞迴版本. 2 * 3 * @param array 傳入要排序的陣列 4 * @param start 傳入要排序的開始位置 5 * @param end ...
- Kotlin笔记
官网: http://kotlinlang.org/ http://kotlinlang.org/docs/reference/ 中文教程: http://kotlindoc.com/ Gradle: ...
- SQL Server 复制订阅
标签:SQL SERVER/MSSQL SERVER/数据库/DBA/高性能解决方案/高可用 概述 配置复制就没有数据库镜像和AlwaysOn的要求那么高,只需要两台服务器能通过TCP进行通讯即可,两 ...
- 2013 duilib入门简明教程 -- 部分bug (11)
一.WindowImplBase的bug 在第8个教程[2013 duilib入门简明教程 -- 完整的自绘标题栏(8)]中,可以发现窗口最大化之后有两个问题, 1.最大化按钮的样式 ...