promise异步编程的原理
一.起源
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异步编程的原理的更多相关文章
- Atitit.异步编程技术原理与实践attilax总结
Atitit.异步编程技术原理与实践attilax总结 1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await1 2. 事件(中断)机制1 3. Await 模 ...
- ES6笔记(7)-- Promise异步编程
系列文章 -- ES6笔记系列 很久很久以前,在做Node.js聊天室,使用MongoDB数据服务的时候就遇到了多重回调嵌套导致代码混乱的问题. JS异步编程有利有弊,Promise的出现,改善了这一 ...
- Atitit. Async await 优缺点 异步编程的原理and实现 java c# php
Atitit. Async await 优缺点 异步编程的原理and实现 java c# php 1. async & await的来源1 2. 异步编程history1 2.1. 线程池 2 ...
- ES6入门八:Promise异步编程与模拟实现源码
Promise的基本使用入门: ——实例化promise对象与注册回调 ——宏任务与微任务的执行顺序 ——then方法的链式调用与抛出错误(throw new Error) ——链式调用的返回值与传值 ...
- Async和Await异步编程的原理
1. 简介 从4.0版本开始.NET引入并行编程库,用户能够通过这个库快捷的开发并行计算和并行任务处理的程序.在4.5版本中.NET又引入了Async和Await两个新的关键字,在语言层面对并行编程给 ...
- async/await actor promise 异步编程
Python协程:从yield/send到async/await http://blog.guoyb.com/2016/07/03/python-coroutine/ Async/Await替代Pro ...
- Promise异步编程解决方案
Promise是ES6中新增的异步编程解决方案,体现在代码中它是一个对象,可以通过 Promise 构造函数来实例化. 其最基本的使用 new Promise(function(resolve,rej ...
- 学习Promise异步编程
JavaScript引擎建立在单线程事件循环的概念上.单线程( Single-threaded )意味着同一时刻只能执行一段代码.所以引擎无须留意那些"可能"运行的代码.代码会被放 ...
- 【ES6】Generator+Promise异步编程
一.概念 首先我们要理解Generator和Promise的概念. Generator:意思是生成器,可以在函数内部通过yeild来控制语句的执行或暂停状态. *Foo(){ yeild consol ...
随机推荐
- centos rabbitmq 安装
MQ 的一个产品[消息队列] rabbitmq 的本质<1>rabbitmq 是用什么语言编写的? => erlang<2>rabbitmq 其实是遵循amqp 协议的一 ...
- Java File类应用:递归遍历文件夹和递归删除文件
要求: 1)采用递归遍历文件夹下的所有文件,包括子文件夹下的文件 2)采用递归删除文件下的所有文件 注意: 以下递归删除文件的方法,只能删除文件,所有的文件夹都还会存在 若要删除正文文件夹,可以在递归 ...
- Yii2项目实现Markdown功能 在线Markdown编辑器
版权声明:本文为博主原创文章,欢迎扩散,扩散请务必注明出处. Yii中添加MarkDown编辑器 主要使用了两个网页Markdown编辑器,都带预览功能. 1,ijackua/yii2-lepture ...
- Web前端的路该怎么走?很迷茫
“路漫漫其修远兮,吾将上下而求索”,这句出自<离骚>. 虽然端午已过,但是还是不影响一个程序员想表(zhuang)达(boy)自己此刻心情的冲动. 偶然路过同事旁边,不(tou)小(kan ...
- String、StringBuffer、StringBuilder比较
String.StringBuffer.StringBuilder三者是字符串中重要的内容,也是面试过程中经常问到的问题,下面就来总结一下三者的区别. 1.三者都可以存储和操作字符串. 2.Strin ...
- 关于sqlmap的一些命令
Options(选项):--version 显示程序的版本号并退出-h, --help 显示此帮助消息并退出-v VERBOSE 详细级别:0-6(默认为1)Target(目标):以下至少需要设置其中 ...
- xshell连接ubuntu
安装了 ubuntu-14 ,为了连接 xshell ,做出的一些配置如下: 1.激活root用户 sudo passwd root 设置新密码,设置成功后会有提示 passwd:password u ...
- Spring学习(14)--- 基于Java类的配置Bean 之 @ImportResource & @Value 注解
学习如何使用@ImportResource 和 @Value 注解进行资源文件读取 例子: 先创建一个MyDriverManager类(模拟读取数据库配置信息) package com.beanann ...
- WPF MVVM 架构 Step By Step(2)(简单的三层架构示例及粘合代码GLUE code)
我们第一步就是去了解三层架构和问题然后去看MVVM是怎么去解决这些问题的. 现在,感觉和事实是完全不同的两个东西.当你看到三层架构的框图的时候,你会觉得每层的职责被分配的很好.但是当你你真的去写代码的 ...
- linux中常用的命令
1.向某个ip发送文件 scp name.tar root(身份)@ip:/lujing 2.重启系统 init 6 3.如果修改了ifcfg-eth0类似于网卡配置文件,修改网口,ip等设置: 需要 ...