Promise对大家来说并不是很陌生,它是一个异步编程的解决方案,主要解决了前端回调地域问题。用阮老师的话说,它“就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果”。

  Promise有三种状态:pending(初始状态)、fulfilled(成功)、reject(失败),初始状态pending只能变成fulfilled或者reject,这一过程是不可逆的,当状态发生改变时,会触发对应的回调方法。除此之外,也支持链式调用,then/catch会返回一个Promise,以供链式调用,盗用MDN上的一张图,Promise的执行流程如下图所示:

  

  具体实现简单分为以下四步:

    1、定义一个执行器fn,自带两个参数的函数,resolve/reject,在实例化Promise时,调用执行器fn,传入参数reslove/reject,初始化回调事件队列taskList
    2、在执行then方法时,判断是不是初始状态pending,如果是,则将then中fullfilled/reject的回调推进执行队列taskList中,then方法返回一个promise实例
    3、实现链式回调中,用id来标识不同的promise实例
    4、当触发了执行器中参数函数时,根据id来判断当前执行的回调方法

  实现代码:

  //公共变量,用于标识MyPromise实例
index = 0;
//promise接收一个回调函数fn,有两个参数,reslove,reject
function MyPromise(fn) {
var _this = this;
//promise的三种状态
this.RESOLVE = "fullfilled";
this.PENDING = "pending";
this.REJECT = "reject";
this.id = index++;
//初始默认状态为penddding
this.state = this.PENDING;
//执行任务列表
this.taskList = [];
//最终执行的回调
this.finallyCallback = null;
//bind改变reslove/reject函数体内this的指向,确保指向MyPromise
fn.call(this, this.resolve.bind(this), this.reject.bind(this));
} MyPromise.prototype.resolve = function(value) {
this.state = this.RESOLVE;
//2、状态变更时,执行完成的方法
this.taskList[this.id] && this.handler(this.taskList[this.id], value);
}; MyPromise.prototype.reject = function(value) {
this.state = this.REJECT;
//2、状态变更时,执行完成的方法
this.taskList[this.id] && this.handler(this.taskList[this.id], value);
};
//执行任务回调
MyPromise.prototype.handler = function(task, value) {
var result = null;
if (this.state === this.RESOLVE) {
result = task.onFullFilled(value);
} else if (this.state === this.REJECT) {
result = task.onReject(value);
}
var nextId = this.id + 1;
//需要判断返回值是不是MyPromise实例,如果是,将之前的任务队列赋值给新的MyPromise实例
if (result instanceof MyPromise) {
result.id = nextId;
result.taskList = this.taskList;
result.finallyCallback = this.finallyCallback;
} else {
//没有返回MyPromise实例
//如果有finally回调,则执行最终的回调
this.finallyCallback && this.finallyCallback();
}
};
//onFullFilled:成功的回调,onReject:失败的回调
MyPromise.prototype.then = function(onFullFilled, onReject) {
var _this = this,
obj = {
onFullFilled: onFullFilled,
onReject: onReject
};
//1、初始化时,将后续可能要执行的任务推送到执行任务队列中
if (this.state === this.PENDING) {
this.taskList.push(obj);
}
//返回一个promise,支持链式调用
return this;
}; //最终执行的方法,不管MyPromise的状态如何
MyPromise.prototype.finally = function(callback) {
this.finallyCallback = callback;
};

  测试代码:

 var cc = new MyPromise(function(reslove, reject) {
setTimeout(function() {
reslove(2);
}, 500);
});
var dd = new MyPromise(function(reslove, reject) {
setTimeout(function() {
reject(3);
}, 500);
});
cc.then(function(num) {
console.log(num);
return dd;
})
.then(
function(cc) {
console.log(cc);
},
function(e) {
console.log(5);
}
)
.finally(function() {
console.log("Game Over");
});
console.log(1);

  执行结果:

  

  实现过程简单粗暴,如有问题,烦请指出,谢谢!

 

手动实现Promise的更多相关文章

  1. 手动实现Promise.all()

    Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例. Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每 ...

  2. 如何手动封装Promise函数

    第一步:Promise构造函数接受一个函数作为参数,该函数的两个参数分别是:resolve和reject; function Promise(task) { // 缓存this let that = ...

  3. js 手动实现 promise.all的功能

    在中高级面试中,实现一个promise.all是一个频率较高的面试题 首先分析下 promise.all(),(参考MDN) 接收一个promise的iterable类型(注:Array,Map,Se ...

  4. (翻译)异步编程之Promise(1):初见魅力

    原文:https://www.promisejs.org/ by Forbes Lindesay 异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2) ...

  5. [WinJS] Promise 用法

    初学 WinJS, 可能对 Promise 的用法不大清楚,本文简要说明一下 WinJS中 promise 的基本用法. 主要参考自:http://try.buildwinjs.com/#promis ...

  6. Q promise API简单翻译

    详细API:https://github.com/kriskowal/q/wiki/API-Reference Q提供了promise的一种实现方式,现在在node中用的已经比较多了.因为没有中文的a ...

  7. Promise详解

    前言 && 基础概念 Promise 是解决 JS 异步的一种方案,相比传统的回调函数,Promise 能解决多个回调严重嵌套的问题. Promise 对象代表一个异步操作,有三种状态 ...

  8. Deferred跟promise跟js同步问题记录

    之前的时候,碰到过几次同事问我,说js的同步怎么处理,就是我想先执行这段代码(耗时相对较长的一行,多数是异步的一些api调用),执行完了之后我再执行下边这句,每次我都很无奈的说不晓得,如果是ajax的 ...

  9. 学习 Promise,掌握未来世界 JS 异步编程基础

    其实想写 Promise 的使用已经很长时间了.一个是在实际编码的过程中经常用到,一个是确实有时候小伙伴们在使用时也会遇到一些问题.Promise 也确实是 ES6 中 对于写 JS 的方式,有着真正 ...

随机推荐

  1. Confluence 6 那些文件需要备份

    备份整个 home 目录是最安全的选项.但是,有很多目录是在 Confluence 启动的时候创建的并且也是可以忽略的.不管那些文件夹可以忽略,下面的文件夹必须进行备份才能回复: <conf-h ...

  2. Confluence 6 修改站点标题

    站点标题是在浏览器的标题栏中显示的.在默认的情况下,标题被显示为 Confluence. 希望修改你站点的标题: 在屏幕的右上角单击 控制台按钮 ,然后选择 General Configuration ...

  3. NHibernate 如何在并行线程下,使用session

    第一,你要知道,并行线程会有一个蛋疼的地方.他不会每次执行都给你去开一个线程. 我一开始以为每次执行都会去开一个新的线程.... list.AsParallel().ForAll(memberInfo ...

  4. Spring JDBC概述

    1.jdbc 概述 Spring JDBC是Spring框架的持久层子框架.用于对数据库的操作(增删改查). 而JdbcTemplate它是spring jdbc子框架中提供的一个操作类,用于对原始J ...

  5. Imperial roads 非严格次小生成树

    cf测评姬比uva快了五倍... /* 不管这条边是不是在mst上,直接跑lca求出路径上的最大边w即可 ans=mst-w+dist(u,v) */ #include<bits/stdc++. ...

  6. HTML添加图像和超链接

    添加图像 <img src="图像的文件地址" alt="加载失败" height="350" width="350&quo ...

  7. Jmeter中常用的一些对字符串的处理

    1)截取部分线程组的名称 group = ctx.getThreadGroup(); // 获取当前线程组 str = group.getName(); // 获取线程组的名称 str = str.s ...

  8. Hadoop ConnectTimeoutException

    晚上继续学习tfidf示例.在跑TwoJob的时候报如下错误,开始以为是node02的防火墙没关好,但看了一下防火墙确实是关了的. 2019-03-30 23:48:19,705 INFO retry ...

  9. C#学习-索引器

    当一个类包含数组成员时,索引器的使用将大大地简化对类中数组成员的访问. 索引器的定义类似于属性,也具有get访问器和set访问器,以下是 [修饰符] 数据类型 this [索引类型index] { g ...

  10. 试验IFTTT同步发微博

    没啥 测试下同步发微博