const PENDING =  'pending';//初始态
const FULFILLED = 'fulfilled';//初始态
const REJECTED = 'rejected';//初始态
function Promise(executor){
let self = this;//先缓存当前promise实例
self.status = PENDING;//设置状态
//定义存放成功的回调的数组
self.onResolvedCallbacks = [];
//定义存放失败回调的数组
self.onRejectedCallbacks = [];
//当调用此方法的时候,如果promise状态为pending,的话可以转成成功态,如果已经是成功态或者失败态了,则什么都不做
//2.1
function resolve(value){ //2.1.1
if(value!=null &&value.then&&typeof value.then == 'function'){
return value.then(resolve,reject);
}
//如果是初始态,则转成成功态
setTimeout(function(){
if(self.status == PENDING){
self.status = FULFILLED;
self.value = value;//成功后会得到一个值,这个值不能改
//调用所有成功的回调
self.onResolvedCallbacks.forEach(cb=>cb(self.value));
}
}) }
function reject(reason){ //2.1.2
setTimeout(function(){
//如果是初始态,则转成失败态
if(self.status == PENDING){
self.status = REJECTED;
self.value = reason;//失败的原因给了value
self.onRejectedCallbacks.forEach(cb=>cb(self.value));
}
}); }
try{
//因为此函数执行可能会异常,所以需要捕获,如果出错了,需要用错误 对象reject
executor(resolve,reject);
}catch(e){
//如果这函数执行失败了,则用失败的原因reject这个promise
reject(e);
};
}
function resolvePromise(promise2,x,resolve,reject){
if(promise2 === x){
return reject(new TypeError('循环引用'));
}
let called = false;//promise2是否已经resolve 或reject了
if(x instanceof Promise){
if(x.status == PENDING){
x.then(function(y){
resolvePromise(promise2,y,resolve,reject);
},reject);
}else{
x.then(resolve,reject);
}
//x是一个thenable对象或函数,只要有then方法的对象,
}else if(x!= null &&((typeof x=='object')||(typeof x == 'function'))){
//当我们的promise和别的promise进行交互,编写这段代码的时候尽量的考虑兼容性,允许别人瞎写
try{
let then = x.then;
if(typeof then == 'function'){
//有些promise会同时执行成功和失败的回调
then.call(x,function(y){
//如果promise2已经成功或失败了,则不会再处理了
if(called)return;
called = true;
resolvePromise(promise2,y,resolve,reject)
},function(err){
if(called)return;
called = true;
reject(err);
});
}else{
//到此的话x不是一个thenable对象,那直接把它当成值resolve promise2就可以了
resolve(x);
}
}catch(e){
if(called)return;
called = true;
reject(e);
} }else{
//如果X是一个普通 的值,则用x的值去resolve promise2
resolve(x);
}
}
//onFulfilled 是用来接收promise成功的值或者失败的原因
Promise.prototype.then = function(onFulfilled,onRejected){
//如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛
//2.2.1
onFulfilled = typeof onFulfilled == 'function'?onFulfilled:function(value){return value};
onRejected = typeof onRejected == 'function'?onRejected:reason=>{throw reason};
//如果当前promise状态已经是成功态了,onFulfilled直接取值
let self = this;
let promise2;
if(self.status == FULFILLED){
return promise2 = new Promise(function(resolve,reject){
setTimeout(function(){
try{
let x =onFulfilled(self.value);
//如果获取到了返回值x,会走解析promise的过程
resolvePromise(promise2,x,resolve,reject);
}catch(e){
//如果执行成功的回调过程中出错了,用错误原因把promise2 reject
reject(e);
}
}) });
}
if(self.status == REJECTED){
return promise2 = new Promise(function(resolve,reject){
setTimeout(function(){
try{
let x =onRejected(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
})
});
}
if(self.status == PENDING){
return promise2 = new Promise(function(resolve,reject){
self.onResolvedCallbacks.push(function(){
try{
let x =onFulfilled(self.value);
//如果获取到了返回值x,会走解析promise的过程
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
} });
self.onRejectedCallbacks.push(function(){
try{
let x =onRejected(self.value);
resolvePromise(promise2,x,resolve,reject);
}catch(e){
reject(e);
}
});
});
} }
//catch原理就是只传失败的回调
Promise.prototype.catch = function(onRejected){
this.then(null,onRejected);
}
Promise.deferred = Promise.defer = function(){
let defer = {};
defer.promise = new Promise(function(resolve,reject){
defer.resolve = resolve;
defer.reject = reject;
});
return defer;
}
function gen(times,cb){
let result = [],count=0;
return function(i,data){
result[i] = data;
if(++count==times){
cb(result);
}
}
}
Promise.all = function(promises){
return new Promise(function(resolve,reject){
let done = gen(promises.length,resolve);
for(let i=0;i<promises.length;i++){
promises[i].then(function(data){
done(i,data);
},reject);
}
});
}
Promise.race = function(promises){
return new Promise(function(resolve,reject){
for(let i=0;i<promises.length;i++){
promises[i].then(resolve,reject);
}
});
}
//返回一个立刻成功的promise
//别人提供 给你一个方法,需要你传入一个promise,但你只有一个普通的值,你就可以通过这个方法把这个普通的值(string number object)转成一个promise对象
Promise.resolve = function(value){
return new Promise(function(resolve){
resolve(value);
});
}
//返回一个立刻失败的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
});
}
module.exports = Promise;

手写基于Promise A+规范的Promise的更多相关文章

  1. 手写一款符合Promise/A+规范的Promise

    手写一款符合Promise/A+规范的Promise 长篇预警!有点长,可以选择性观看.如果对Promise源码不是很清楚,还是推荐从头看,相信你认真从头看到尾,并且去实际操作了,肯定会有收获的.主要 ...

  2. 带你手写基于 Spring 的可插拔式 RPC 框架(一)介绍

    概述 首先这篇文章是要带大家来实现一个框架,听到框架大家可能会觉得非常高大上,其实这和我们平时写业务员代码没什么区别,但是框架是要给别人使用的,所以我们要换位思考,怎么才能让别人用着舒服,怎么样才能让 ...

  3. 一步一步实现一个Promise A+规范的 Promise

    2015年6月,ES2015(即ES6)正式发布后受到了非常多的关注.其中很重要的一点是 Promise 被列为了正式规范. 在此之前很多库都对异步编程/回调地狱实现了类 Promise 的应对方案, ...

  4. 手写符合Promise/A+规范的Promise

    const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "r ...

  5. 带你手写基于 Spring 的可插拔式 RPC 框架(三)通信协议模块

    在写代码之前我们先要想清楚几个问题. 我们的框架到底要实现什么功能? 我们要实现一个远程调用的 RPC 协议. 最终实现效果是什么样的? 我们能像调用本地服务一样调用远程的服务. 怎样实现上面的效果? ...

  6. 带你手写基于 Spring 的可插拔式 RPC 框架(二)整体结构

    前言 上一篇文章中我们已经知道了什么是 RPC 框架和为什么要做一个 RPC 框架了,这一章我们来从宏观上分析,怎么来实现一个 RPC 框架,这个框架都有那些模块以及这些模块的作用. 总体设计 在我们 ...

  7. 带你手写基于 Spring 的可插拔式 RPC 框架(五)注册中心

    注册中心代码使用 zookeeper 实现,我们通过图片来看看我们注册中心的架构. 首先说明, zookeeper 的实现思路和代码是参考架构探险这本书上的,另外在 github 和我前面配置文件中的 ...

  8. 带你手写基于 Spring 的可插拔式 RPC 框架(四)代理类的注入与服务启动

    上一章节我们已经实现了从客户端往服务端发送数据并且通过反射方法调用服务端的实现类最后返回给客户端的底层协议. 这一章节我们来实现客户端代理类的注入. 承接上一章,我们实现了多个底层协议,procoto ...

  9. 手写一个Promise/A+,完美通过官方872个测试用例

    前段时间我用两篇文章深入讲解了异步的概念和Event Loop的底层原理,然后还讲了一种自己实现异步的发布订阅模式: setTimeout和setImmediate到底谁先执行,本文让你彻底理解Eve ...

随机推荐

  1. jquery的封装与对象学习

    1.封装学习 /// <reference path="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js" /> ...

  2. php弱语言特性-计算科学计数法

    php处理字符串时存在一个缺陷问题,如果字符串为“1e1”,本该是一个正常的字符串,但是php会将它认为是科学计数法里面的e: 也就是按照数学的科学计数法来说:1e1=10^1=10,因此php会把这 ...

  3. LaTeX 技巧 802:国内期刊 CCT 模板编译经验

    国内有不少期刊依旧在使用过时的 CCT 方式来支持中文,这些模板非常相似,似乎系出同源.由于这些模板在现代的 TeX 发行版内无法正确编译,对不少投稿人造成困扰,所以我写下这篇文章,希望对投稿人有一些 ...

  4. Linux网络课程学习第一天

    第一天上课主要介绍了LINUX系统和Linux课程的情况.了解了开源系统的四大优势,六大特点. 最具有心得的一句话: 学习是件苦差事: 稻盛和夫先生的话也深深激励着我:“工作马马虎虎,只想在兴趣和游戏 ...

  5. 大json直接序列化成dataset

    rtnDs= JsonConvert.DeserializeObject<DataSet>(strBuff);

  6. C 库函数 - fmod()

    C 库函数 - fmod() 转自: C 标准库 - <math.h> 描述 C 库函数 double fmod(double x, double y) 返回 x 除以 y 的余数. 声明 ...

  7. Vue前端挂载对象时一些思考

    最近,在Vue前端调试http请求,无论如何如何也是拦截不了某些http请求.场景是这样的:Java后端组装好Vue对象,然后送到前端,前端通过id来挂载该Vue对象,而该对象中有上传文件或者图片的控 ...

  8. Python 绘图 cookbook

    目录 python绘图常见bug matplotlib包加载 解决中文绘图乱码解决方法 解决python中用matplotlib画多幅图时出现图形部分重叠的问题 python绘图常见bug matpl ...

  9. 百度网盘无vip高速下载的方法

    我拿的是谷歌浏览器做实验 首先下载一个可以改user-agent的插件 我chorm里面下载的是User-Agent Switcher for Chrome插件 将百度网盘的url地址中的baidu. ...

  10. eclipse unable to start within 45 seconds

    在eclipse4.8.2中运行tomcat8.5项目时,提示出错: Server Tomcat v8.0 Server at localhost was unable to start within ...