手动实现Promise
时间:2022-07-24
本文章向大家介绍手动实现Promise,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
手动实现Promise
JavaScript
是单线程的语言,通过维护执行栈与任务队列而实现了异步操作,setTimeout
与Ajax
就是典型的异步操作,Promise
就是异步操作的一个解决方案,用于表示一个异步操作的最终完成或失败, 及其结果值。
语法
new Promise( function(resolve, reject) { /* executor */
// 执行代码 需要指明resolve与reject的回调位置
});
executor
是带有resolve
和reject
两个参数的函数。Promise
构造函数执行时立即调用executor
函数,resolve
和reject
两个函数作为参数传递给executor
。resolve
和reject
函数被调用时,分别将promise
的状态改为完成fulfilled
或失败rejected
。executor
内部通常会执行一些异步操作,一旦异步操作执行完毕,要么调用resolve
函数来将promise
状态改成fulfilled
,要么调用reject
函数将promise
的状态改为rejected
。如果在executor
函数中抛出一个错误,那么该promise
状态为rejected
,executor
函数的返回值被忽略。
状态
Promise
本质上就是一个状态机,完整的说是有限状态自动机,给定当前输入与状态,那么输出是可以明确计算的。
pending: 初始状态,既不是成功,也不是失败状态。
fulfilled: 意味着操作成功完成。
rejected: 意味着操作失败。
Promise
对象只有从pending
变为fulfilled
和从pending
变为rejected
的状态改变。只要处于fulfilled
和rejected
,状态就不会再变了。
实现
// 定义_Promise构造函数
function _Promise(fn) {
this.status = "pending"; // 定义属性存储状态 // 赋予初始状态pending
this.value = null; // resolve的value
this.reason = null; // reject的reason
this.onFulfilled = []; // 存储then方法中注册的第一个回调函数
this.onReject = []; // 存储then方法中注册的第二个回调函数
var handler = funct => { // 事件处理函数
if(typeof(funct) === "function") { // 如果是函数的话才进行执行
if(this.status === "fulfilled") funct(this.value); // 执行并传递value
if(this.status === "rejected") funct(this.reason); // 执行并传递rejected
}
}
// 实现resolve回调
var resolve = value => { // 使用箭头函数主要是为了绑定this指向
this.status = "fulfilled"; // 设置状态
this.value = value; // 得到结果
if(value instanceof _Promise){ // 判断返回的值是否为Promise实例
value.onFulfilled = this.onFulfilled; // 是则以此链式调用
return value;
}
setTimeout(() => { // 使用setTimeout是为了将回调函数置于任务队列,不阻塞主线程,异步执行,实际promise的回调是置于微队列的,而setTimeout的回调是置于宏队列
try {
this.onFulfilled.forEach(handler); // 交予事件处理
}catch (e){
console.error(`Error in promise: ${e}`); // 打印异常
reject(e); // reject
}
}, 0)
}
// 实现rejected
var reject = reason => { // 使用箭头函数主要是为了绑定this指向
this.status = "rejected"; // 设置状态
this.reason = reason; // 得到结果
setTimeout(() => { // 置于任务队列
try {
this.onReject.forEach(handler); // 交予事件处理
}catch (e){
console.error(`Error in promise: ${e}`); // 打印异常
}
}, 0)
}
fn(resolve, reject); // 执行
}
// 定义then
// value接收上层结果 --- function处理自身逻辑 --- return传递到下层
_Promise.prototype.then = function(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v; // 转为函数
onRejected = typeof onRejected === 'function' ? onRejected : r => r; // 转为函数
return new _Promise((resolve, reject) => { // 返回一个新的_Promise
this.onFulfilled.push((value) => { // 将回调函数置于onFulfilled
resolve(onFulfilled(value)); // 执行并传递
});
this.onReject.push((value) => { // 将回调函数置于onReject
reject(onRejected(value)); // 执行并传递
});
})
}
// 测试
var promise = new _Promise(function(resolve,reject){
var rand = Math.random() * 2;
setTimeout(function(){
if(rand < 1) resolve(rand);
else reject(rand);
},1000)
})
promise.then((rand) => {
console.log("resolve",rand); // resolve回调执行
}, (rand) => {
console.log("reject",rand); // reject回调执行
}).then(function(){ // resolve后继续执行
return new _Promise(function(resolve,reject){
var rand = Math.random() * 2;
setTimeout(function(){
resolve(rand);
},1000)
})
}).then(function(num){ // resolve后继续执行
console.log(num,"继续执行并接收参数");
return 1;
}).then(function(num){
console.log(num,"继续执行并接收参数");
})
/*
实现的_Promise比较简单
实际使用的Promise比较复杂,有各种情况的考虑
例子中仅实现了Promise构造函数与then,实际中还有catch、Promise.all、Promise.race、Promise.resolve、Promise.reject等实现
*/
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://zhuanlan.zhihu.com/p/47434856
https://www.jianshu.com/p/27735abb91eb
https://segmentfault.com/a/1190000013170460
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 浅谈thinkphp的nginx配置,以及重写隐藏index.php入口文件方法
- php图片裁剪函数
- Laravel自定义 封装便捷返回Json数据格式的引用方法
- Laravel模糊查询区分大小写的实例
- laravel实现一个上传图片的接口,并建立软链接,访问图片的方法
- Laravel中validation验证 返回中文提示 全局设置的方法
- laravel5表单唯一验证的实例代码
- 实现laravel 插入操作日志到数据库的方法
- laravel validate 设置为中文的例子(验证提示为中文)
- Laravel 使用查询构造器配合原生sql语句查询的例子
- php面试实现反射注入的详细方法
- laravel框架 api自定义全局异常处理方法
- laravel实现于语言包的完美切换方法
- PHP校验15位和18位身份证号的类封装
- 用Echarts打造一个轮播图!