一.起源

JavaScript中的异步由来已久,不论是定时函数,事件处理函数还是ajax异步加载都是异步编程的一种形式,我们现在以nodejs中异步读取文件为例来编写一个传统意义的异步函数:

var fs = require('fs');
function readJSON(filename,callback){
fs.readFile(filename,'utf8',function(err,res){
if(err){
return callback(err,null);
}
try{
var res = JSON.parse(res);
}catch(ex){
callback(ex)
}
callback(null,res);
});
}

如果我们想异步读取一个json文件,它接受2个参数,一个文件名,一个回调函数。文件名必不可少,关键就在这个callback上面了,当我们要执行这个readJSON函数时,要自己构造想要的回调函数,但是在readJSON函数内部传递callback时候不知道他的参数,显然是不友好的。下面在看一种异步编程的代码:

fs.readFile('file1.txt','utf8',function(err,res){
fs.readFile('file2.txt','utf8',function(err,res){
fs.readFile('file2.txt','utf8',function(err,res){
console.log(res);
});
});
});

这里嵌套了3个异步回调函数,他们的执行时刻都是不可预测的并且这样写代码也不符合普通程序的执行流程。

所以,问题来了,promise提供了一个解决上述问题的模式。

二.定义

promise是对异步编程的一种抽象。它是一个代理对象,代表一个必须进行异步处理的函数返回的值或抛出的异常。也就是说promise对象代表了一个异步操作,可以将异步对象和回调函数脱离开来,通过then方法在这个异步操作上面绑定回调函数。

下面介绍具体API,这里遵循的是commonJS promise/A+规范。

1.状态

promise有3种状态:pending(待解决,这也是初始化状态),fulfilled(完成),rejected(拒绝)。

2.接口

promise唯一接口then方法,它需要2个参数,分别是resolveHandler和rejectedHandler。并且返回一个promise对象来支持链式调用。

promise的构造函数接受一个函数参数,参数形式是固定的异步任务,举一个栗子:

function sendXHR(resolve, reject){
var xhr = new XMLHttpRequest();
xhr.open('get', 'QueryUser', true);
xhr.onload = function(){
if((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304){
resolve(xhr.responseText);
}else{
reject(new Error(xhr.statusText));
}
};
xhr.onerror = function(){
reject(new Error(xhr.statusText));
}
xhr.send(null)
}

三.实现

要实现promise对象,首先要考虑几个问题:

1.promise构造函数中要实现异步对象状态和回调函数的剥离,并且分离之后能够还能使回调函数正常执行

2.如何实现链式调用并且管理状态

首先是构造函数:

//全局宏定义
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
//Promise构造函数
function Promise(fn){
var self = this;
self.state = PENDING;//初始化状态
self.value = null;//存储异步结果的对象变量
self.handlers = [];//存储回调函数,这里没保存失败回调函数,因为这是一个dome
//异步任务成功后处理,这不是回调函数
function fulfill(result){
if(self.state === PENDING){
self.state = FULFILLED;
self.value = result;
for(var i=0;i<self.handlers.length;i++){
self.handlers[i](result);
} }
} //异步任务失败后的处理,
function reject(err){
if(self.state === PENDING){
self.state = REJECTED;
self.value = err;
}
}
fn&&fn(fulfill,reject); };

构造函数接受一个异步函数,并且执行这个异步函数,修改promise对象的状态和结果。

回调函数方法then:

//使用then方法添加回调函数,把这次回调函数return的结果当做return的promise的resolve的参数
Promise.prototype.then = function(onResolved, onRejected){
var self = this;
return new Promise(function(resolve, reject){
var onResolvedFade = function(val){
var ret = onResolved?onResolved(val):val;//这一步主要是then方法中传入的成功回调函数通过return来进行链式传递结果参数
if(Promise.isPromise(ret)){//回调函数返回值也是promise的时候
ret.then(function(val){
resolve(val);
});
}
else{
resolve(ret);
}
};
var onRejectedFade = function(val){
var ret = onRejected?onRejected(val):val;
reject(ret);
};
self.handlers.push(onResolvedFade);
if(self._status === FULFILLED){
onResolvedFade(self._value);
} if(self._status === REJECTED){
onRejectedFade(self._value);
}
});
}

通过上面的代码可以看出,前面提出的2个问题得到了解决,1.在promise对象中有3个属性,state,value,handlers,这3个属性解决了状态和回调的脱离,并且在调用then方法的时候才将回调函数push到handlers属性上面(此时state就是1,可以在后面的代码中执行onResolve)2.链式调用通过在then方法中返回的promise对象实现,并且通过onResolvedFade将上一个回调的返回值当做这次的result参数来执行进行传递。

测试代码:

function async(value){
var pms = new Promise(function(resolve, reject){
setTimeout(function(){
resolve(value);;
}, 1000);
});
return pms;
}
async(1).then(function(result){
console.log('the result is ',result);//the result is 2
return result;
}).then(function(result){
console.log(++result);//
});

总之,不同框架对promise的实现大同小异,上面的代码是ECMASCRIPT6标准的promise简单实现。jquery和其他框架也有实现,不过听说jquery的实现很糟糕- -!

promise异步编程的原理的更多相关文章

  1. Atitit.异步编程技术原理与实践attilax总结

    Atitit.异步编程技术原理与实践attilax总结 1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await1 2. 事件(中断)机制1 3. Await 模 ...

  2. ES6笔记(7)-- Promise异步编程

    系列文章 -- ES6笔记系列 很久很久以前,在做Node.js聊天室,使用MongoDB数据服务的时候就遇到了多重回调嵌套导致代码混乱的问题. JS异步编程有利有弊,Promise的出现,改善了这一 ...

  3. Atitit. Async await 优缺点 异步编程的原理and实现 java c# php

    Atitit. Async await 优缺点 异步编程的原理and实现 java c# php 1. async & await的来源1 2. 异步编程history1 2.1. 线程池 2 ...

  4. ES6入门八:Promise异步编程与模拟实现源码

    Promise的基本使用入门: ——实例化promise对象与注册回调 ——宏任务与微任务的执行顺序 ——then方法的链式调用与抛出错误(throw new Error) ——链式调用的返回值与传值 ...

  5. Async和Await异步编程的原理

    1. 简介 从4.0版本开始.NET引入并行编程库,用户能够通过这个库快捷的开发并行计算和并行任务处理的程序.在4.5版本中.NET又引入了Async和Await两个新的关键字,在语言层面对并行编程给 ...

  6. async/await actor promise 异步编程

    Python协程:从yield/send到async/await http://blog.guoyb.com/2016/07/03/python-coroutine/ Async/Await替代Pro ...

  7. Promise异步编程解决方案

    Promise是ES6中新增的异步编程解决方案,体现在代码中它是一个对象,可以通过 Promise 构造函数来实例化. 其最基本的使用 new Promise(function(resolve,rej ...

  8. 学习Promise异步编程

    JavaScript引擎建立在单线程事件循环的概念上.单线程( Single-threaded )意味着同一时刻只能执行一段代码.所以引擎无须留意那些"可能"运行的代码.代码会被放 ...

  9. 【ES6】Generator+Promise异步编程

    一.概念 首先我们要理解Generator和Promise的概念. Generator:意思是生成器,可以在函数内部通过yeild来控制语句的执行或暂停状态. *Foo(){ yeild consol ...

随机推荐

  1. centos nginx-1.10.3 安装

    wget http://nginx.org/download/nginx-1.13.1.tar.gz nginx 依赖 pcre 库,要先安装pcre,因为nginx 要在rewrite 要解析正则表 ...

  2. Implement a Linked List

    https://github.com/Premiumlab/Python-for-Algorithms--Data-Structures--and-Interviews/blob/master/Lin ...

  3. redis学习(1)--- NoSQL介绍

    一.NoSQL介绍 1.什么是NoSQL NoSQL = Not Only SQL 非关系型数据库 2.为什么用NoSQL High performance - 高并发读写 Huge Storage ...

  4. Vue爬坑之vuex初识

    在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用  props 或者 $emit 等方式 http://www.cnblogs.com/wisewrong/p/62660 ...

  5. winform中的 datagriview 字段自动填充长度

    在winfrom 的 datagridview 中 绑定字段 经常回在最后面空出一部分来,显得不美观, 现在教大家如何让它自适应宽度 public static void Autogrid(DataG ...

  6. 上下文Context详细介绍

    1.先看看它的继承结构,下图可以看出Context首先是一个抽象类,继承了Object,Activity,Service,Application都继承了它 2.API中对它的描述: @1Context ...

  7. css样式表的选择器与分类

    css 样式表的作用: 主要用于结构,样式与行为,CSS主要的作用就是美化网页的一个语言,它的特点: 1.结构与样式分离的方式,便于后期维护与改版; 2.样式定义精确到像素的级别; css样式表的结构 ...

  8. JMS 之 Active MQ 消息存储

    一.消息的存储方式 ActiveMQ支持JMS规范中的持久化消息与非持久化消息 持久化消息通常用于不管是否消费者在线,它们都会保证消息会被消费者消费.当消息被确认消费后,会从存储中删除 非持久化消息通 ...

  9. JS事件及其兼容用法

    JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间. 1.事件流:描述的是从页面中接收事件的顺序. IE提出的事件冒泡流:事件开始由最具体的 ...

  10. ajax、PHP、session做购物车

    购物车网页代码 1.登录界面login.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...