Promise 解析
Promise
由于js的语言特性(用户交互)和工作环境(浏览器脚本),决定了它是单线程工作,所以两段脚本不能同时运行,但为了实现功能,所以人们使用了事件和回调来初步解决这个问题,例如(addEventListener),但这也带来了严重的回调问题,非常容易陷入回调地狱的困恼,
由于这个问题。js发展至今,社区提出了promise(承若)标准,被es6写入了语言标准中,统一了它的用法,并在原生中提供了标准的Promise对象
让我们先来实例化一个标准的promise对象:
//实例化一个promise对象,这个对象有两个参数(resolve-决定,reject-拒绝)
let promise = new Promise((resolve,reject)=>{
//延时3s,把promise的状态改为resolve-决定
setTimeout(function(){
resolve('666')
},3000)
})
//每个实例都有then()方法,用来获取其值或原因。
//then(onFulfilled, onRejected)
//成功的回调,失败的回调
promise.then(data=>{
console.log(data)
},err=>{
console.error(err)
}).then()
同时promise还可以多次调用then()方法,也可以在resolve中继续抛出一个新的promise 例:
promise.then(function(data){
console.log('data2=',data);
},function(err){
console.log('err2=',err);
});
或者:
let promise2 = promise.then(function(data){
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve(data + '777' );
},1000);
});
});
当然还有常见的all(),catch(),resolve(),reject()等等一些方法,而这些方法都是按照Promise/A+规范规定的 (详情)
我们现在就按照这个规范来实现一个属于我们自己的promise
首先我们先定义出这个类:
// executor是一个执行函数,在实例化的时候被传入。这个函数会执行两个被传入的状态函数
var Promise = function (executor) {
let self = this;
//没个promise都会有个初始化值,这个值在规范中叫做pending
self.status = 'pending';
self.value = undefined; // 默认成功的值
self.reason = undefined; // 默认失败的原因
self.onResolvedCallbacks = []; // 存放then成功的回调
self.onRejectedCallbacks = []; // 存放then失败的回调
// 成功状态要执行的函数
function resolve(value) {
//更改他的状态值,为成功,且不能更改
if (self.status === 'pending') {
self.status = 'resolved';
self.value = value;
//实例多次调用then(),循环释放数组
self.onResolvedCallbacks.forEach(function (fn) {
fn();
});
}
}
// 失败状态要执行的函数
function reject(reason) {
//更改他的状态值,为失败,且不能更改
if (self.status === 'pending') {
self.status = 'rejected';
self.reason = reason;
//实例多次调用then(),循环释放数组
self.onRejectedCallbacks.forEach(function (fn) {
fn();
})
}
}
如果直接传入错误的代码,那么直接进入reject
try {
executor(resolve, reject)
} catch (e) {
// 捕获的时候发生异常,就直接失败了
reject(e);
}
}
下面我们来实现then()方法,个方法每个实例都有,他是一个方法,所以我们把它挂载到Promise原型上:
Promise.prototype.then = function (onFulfilled, onRjected) {
//成功和失败默认一个函数,防止报错,
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : function (value) {
return value;
}
onRjected = typeof onRjected === 'function' ? onRjected : function (err) {
throw err;
}
let self = this;
//定义一个返回的promise
let promise2;
//当状态是成功的时候,可能会在函数中再次返回一个promise
if (self.status === 'resolved') {
promise2 = new Promise(function (resolve, reject) {
// 当成功或者失败执行时有异常那么返回的promise应该处于失败状态
//这个x 是第一个promise执行后的结果
// x可能是一个promise 也有可能是一个普通的值
setTimeout(function () {
try {
let x = onFulfilled(self.value);
// x可能是别人promise,写一个方法统一处理
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
//当状态是失败的时候
if (self.status === 'rejected') {
promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
let x = onRjected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
// 当调用then时可能没成功 也没失败
if (self.status === 'pending') {
promise2 = new Promise(function (resolve, reject) {
// 此时没有resolve 也没有reject
self.onResolvedCallbacks.push(function () {
setTimeout(function () {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
})
});
self.onRejectedCallbacks.push(function () {
setTimeout(function () {
try {
let x = onRjected(self.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
})
}
return promise2;
}
集中处理x
function resolvePromise(promise2, x, resolve, reject) {
// 有可能这里返回的x是别人的promise
// 先跑错
if (promise2 === x) { //这里应该报一个类型错误,有问题
return reject(new TypeError('循环引用了'))
}
// 看x是不是一个promise,promise应该是一个对象
let called; // 表示是否调用过成功或者失败
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
//根据语法规定的几种情况来判断
// 可能是promise {},看这个对象中是否有then方法,如果有then我就认为他是promise了
try {
let then = x.then;
if (typeof then === 'function') {
// 成功
then.call(x, function (y) {
if (called) return
called = true
// y可能还是一个promise,在去解析直到返回的是一个普通值
//递归调用这个函数,
resolvePromise(promise2, y, resolve, reject)
}, function (err) { //失败
if (called) return
called = true
reject(err);
})
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true;
reject(e);
}
} else { // 说明是一个普通值1
resolve(x); // 表示成功了
}
}
在实现了这些之后,其他的方法,更多的就是一个语法糖,我们来实现他们
catch:
catch实际上就是reject,所以一般建议在then里面不穿reject(),而链式调用catch方法
Promise.prototype.catch = function (callback) {
return this.then(null, callback)
}
all
//会传入一个数组,这个数组是promise集合
Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
//arr是最终返回值的结果
let arr = [];
// 表示成功了多少次
let i = 0;
function processData(index, y) {
arr[index] = y;
if (++i === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(function (y) {
processData(i, y)
}, reject)
}
})
}
race
//race就是赛跑的意思,谁获取结果比较快,就返回谁
// 只要有一个promise成功了 就算成功。如果第一个失败了就失败了
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for (var i = 0; i < promises.length; i++) {
promises[i].then(resolve,reject)
}
})
}
// 生成一个成功的promise
Promise.resolve = function(value){
return new Promise(function(resolve,reject){
resolve(value);
})
}
// 生成一个失败的promise
Promise.reject = function(reason){
return new Promise(function(resolve,reject){
reject(reason);
})
}
defer 延期处理
会包容promise 可用于封装在传递方法之外调用原有的promise回调
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise(function (resolve, reject) {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd
}
Promise 解析的更多相关文章
- Promise解析(待完成)
Promise是一种异步操作的解决方案,将写法复杂的传统的回调函数和监听事件的异步操作,用同步代码的形式表达出来.避免了多级异步操作的回调函数嵌套. 1.主要用于异步计算 2.可以将异步操作队列化,按 ...
- Promise,Generator(生成器),async(异步)函数
Promise 是什么 Promise是异步编程的一种解决方案.Promise对象表示了异步操作的最终状态(完成或失败)和返回的结果. 其实我们在jQuery的ajax中已经见识了部分Promise的 ...
- Netty源码解析—客户端启动
Netty源码解析-客户端启动 Bootstrap示例 public final class EchoClient { static final boolean SSL = System.getPro ...
- 基于PromiseA+规范实现一个promise
实现如果下规范的promise Aplus规范 1,promise是一个类:有三个状态 pending/等待态 fulfilled/成功态 rejected/失败态 2,promise默认执行器立即执 ...
- AngularJS之代码风格36条建议【一】(九)
前言 其实在新学一门知识时,我们应该注意下怎么书写代码更加规范,从开始就注意养成一个良好的习惯无论是对于bug的查找还是走人后别人熟悉代码都是非常好的,利人利己的事情何乐而不为呢,关于AngularJ ...
- 使用 Promises 编写更优雅的 JavaScript 代码
你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别.难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它 ...
- ES6核心内容精讲--快速实践ES6(三)
Promise 是什么 Promise是异步编程的一种解决方案.Promise对象表示了异步操作的最终状态(完成或失败)和返回的结果. 其实我们在jQuery的ajax中已经见识了部分Promise的 ...
- Netty源码分析(三):客户端启动
Bootstrap Bootstrap主要包含两个部分,一个是服务器地址的解析器组AddressResolverGroup,另一个是用来工作的EventLoopGroup. EventLoopGrou ...
- js async await 终极异步解决方案
既然有了promise 为什么还要有async await ? 当然是promise 也不是完美的异步解决方案,而 async await 的写法看起来更加简单且容易理解. 回顾 Promise Pr ...
随机推荐
- VS Code 上那些沙雕插件
本文整理自网络,作者不详,如有侵权,则可删除. VS Code 作为前端最牛逼的一个前端编辑器,可以说是最流行的开发工具了,以其可支持扩展程序(通过安装扩展程序,VS Code 可以支持更多新的语言. ...
- 前端学习(十一):CSS性质
进击のpython ***** 前端学习--CSS性质 那在CSS上还有一些很重要的性质:继承性,层叠性以及特殊性 那本小节就基于这三个性质进行展开... ... 继承性 在CSS的某些样式是具有继承 ...
- 痞子衡嵌入式:恩智浦i.MX RTxxx系列MCU特性那些事(1)- 概览
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是恩智浦i.MX RTxxx系列MCU的基本特性. 恩智浦半导体于2017年开始推出的i.MX RT系列重新定义了MCU,其第一款芯片i. ...
- lua中 string.find(查找获取字符串) string.gsub(查找替换字符串) string.sub(截取字符串)
> aaa='/p/v2/api/winapi/adapter/lgj'> print(string.find(aaa, "^/.+/adapter/(.*)"))1 ...
- 解决移动端rem加载瞬间页面错乱的方法(放大或者缩小)
移动端布局有很多种,这里我们最常使用到rem+百分比的布局方式(高度/字体设置rem单位,宽度设置百分比)来处理屏幕兼容,这种方法在兼容上是比较不错的,可以使得字体以及整体适应各种大小的屏幕,可以解决 ...
- 学习JavaScript数据结构与算法 2/15
第一章 JavaScript简介 js不同于C/C++,C#,JAVA,不是强类型语言. 通常,代码质量可以用全局变量和函数的数量来考量(数量越多越糟).因此,尽可能避免使用全局变量. JS数据类型 ...
- Python 变量类型及变量赋值
在 Python 中,变量不一定占用内存变量.变量就像是对某一处内存的引用,可以通过变量访问到其所指向的内存中的值,并且可以让变量指向其他的内存.在 Python 中,变量不需要声明,但是使用变量之前 ...
- 因为不知道Java的CopyOnWriteArrayList,面试官让我回去等通知
先看再点赞,给自己一点思考的时间,微信搜索[沉默王二]关注这个靠才华苟且的程序员.本文 GitHub github.com/itwanger 已收录,里面还有一线大厂整理的面试题,以及我的系列文章. ...
- Python Tuple(元组) cmp()方法
描述 Python 元组 cmp() 函数用于比较两个元组元素.高佣联盟 www.cgewang.com 语法 cmp()方法语法: cmp(tuple1, tuple2) 参数 tuple1 -- ...
- CMD使用笔记
CMD杂谈 基本功: 1,列出所有任务及进程号,杀进程 tasklist tasklist /? 获取使用帮助 taskkill taskkill /? 获取使用帮助 2,cd 切换目录 cd ...