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. es6简单小复习

    Ecmascript 6 ECMAScript 6.0(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了. Ecmascript 是 JavaScript 语言的 ...

  2. CSS实现同一行中图片和文本垂直居中

    1.为图片和文本都设置vertical-align:middle

  3. 输出《Harry Potter and the Sorcerer's Stone》文本中的前N个最长用的英文单词及其数量

    输出<Harry Potter and the Sorcerer's Stone>文本中的前N个最长用的英文单词及其数量 实验思路: 1. 利用输入流将文件当中内容读入. 2. 将文件内容 ...

  4. EF Code-First(Oracle)通过Migration来更新数据库的表的字段

    关于Oracle中使用Entity Framework 6.x Code-First方式开发,请参考博客(菩提树下的杨过)https://www.cnblogs.com/yjmyzz/p/how-to ...

  5. Wannafly Camp 2020 Day 3D 求和 - 莫比乌斯反演,整除分块,STL,杜教筛

    杜教筛求 \(\phi(n)\), \[ S(n)=n(n+1)/2-\sum_{d=2}^n S(\frac{n}{d}) \] 答案为 \[ \sum_{d=1}^n \phi(d) h(\fra ...

  6. 解决shell 报错:syntax error: unexpected end of file

    debug  shell:执行 sh -x test.sh vi test.sh :set fileformat=unix :wq解决问题原因是我在windows pycharm 写的格式不符合uni ...

  7. http断点续传Range与Content-Range

    今天用别人封装的libcurl库下载文件,发现下载下来的文件总是缺少头两个字节,用以下配置启用HTTP头信息打印后发现原来是设置了断点续传位置的原因 curl_easy_setopt(m_pCurl, ...

  8. Hibernate 和Mybatis的区别

    Hibernate 和Mybatis的区别   1.hibernate 入门门槛高,是一个标准的ORM框架(对象关系映射),不需要程序写sql,sql语句自动生成,对sql语句进行优化.修改比较困难. ...

  9. sql 注释解释

    1 2 3 4 CREATE TABLE groups(   gid INT PRIMARY KEY AUTO_INCREMENT COMMENT '设置主键自增',   gname VARCHAR( ...

  10. GitBook的使用方式,快速创建网页文档

    环境需求:node npm 得装好 ----------------------------------- 我一开始不知道得先装gitbook-cli 先执行了 npm install gitbook ...