前言
学习是一个漫长的过程,需要循序渐进,要想深入的理解一门技术,需要沉下心来慢慢研究。要做到通过现象看本质,学Promise的同时也会用到高阶函数和发布订阅,只有掌握了那些通用的技术,才能够更有效的学习下去,更好的看到本质。慢慢的你会发现通过深入学习一个Promise,收获的却不只是Promise。
一、什么是Promise
Promise 是异步编程的一种解决方案,Promise对象是一个构造函数,用来生成Promise实例.
二、Promise对象有以下两个特点。
1、有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
2、一旦状态改变,就不会再变,Promise对象的状态改变只有两种可能: 从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果
三、Promise的实现(ES5)
1、名词解释:
1、executor:为执行器当new Promsie(executor)的时候,executor作为同步代码立即执行。
2、status:Promise实例的三个状态pending(进行中)、fulfilled(已成功)和rejected(已失败)
3、value:这个是成功传递的参数,成功有成功的值。
4、reason:这个是失败时候传递的参数,失败有失败的原因。
5、resolve:一个成功时调用的函数,作为参数传递给executor,为高阶函数
6、reject:一个失败时调用的函数,作为参数传递给executor,为高阶函数
2、最基础的Promise:
最基础的promise源码只有34行,看懂了这34行代码,你就懂得了promise的最核心部分,是不是很激动!!!
代码解读:
在Promise当中,定义好状态,成功的值,和失败的原因,当你传入
function(resolve,reject){resolve('成功了')}的时候resolve作为回调函数,
被触发执行了,然后之前定义的状态pending(等待)变成了fulfilled(成功),
此时调用then方法传入两个callback,通过内部比对if来执行onFulfilled或
onRejected。
function Promise(executor){
const self = this;
self.status = 'pending';//promise 状态
self.value = undefined;// 成功有成功的值
self.reason = undefined;// 失败有失败的原因
function resolve(value){
if(self.status === 'pending'){ //只有pending状态下才可以改变状态
self.status = 'fulfilled';
self.value = value;
}
}
function reject(reson){
if(self.status === 'pending'){//只有pending状态下才可以改变状态
self.status = 'rejected';
self.reason = reson;
}
}
try{
executor(resolve,reject); // 此处为高阶函数,一个函数内传入其他函数,这就是高阶函数的一种
}catch(err){
reject(err);
}
}
Promise.prototype.then = function(onFulfilled,onRejected){
const self = this;
if(self.status === 'fulfilled'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
}
上述代码可以正常运行以下代码:
const p = new Promise((resolve,reject)=>{
resolve('成功')
// throw 1213
// reject('失败')
});
p.then(function(data){
console.log(data) // 成功
},function(err){
console.log(err) // 失败 或 1213
})
到这里最基本的Promise已经封装完成了,是不是很简单。
3、如何解决异步调用?
上面封装的代码如果遇到下面的代码是无结果的。
同步代码的执行顺序是:executor ---> resolve ---> then异步代码的执行顺序是:executor ---> then ---> resolve
所以此时调用then方法的时候,记得看then方法的实现哦,他的内部status 状态是pending,回想一下之前同步的实现,到这里会有成功或者失败的状态,但这次是异步的情况,resolve要在then之后执行,所以这里要用到发布订阅模式(可以理解为,把callback装进数组中就是订阅,当循环数组执行的时候就是发布),对应的关系就是onResolvedCallbacks装着then方法成功的回调函数onFulfilled,onRejectedCallbacks装着then方法失败的回调函数onRejected,当回调调用resolve的时候循环执行就行了
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('我是异步的成功')
})
});
为了解决异步更新代码如下:
function Promise(executor){
const self = this;
self.status = 'pending';//promise 状态
self.value = undefined;// 成功有成功的值
self.reason = undefined;// 失败有失败的原因
+ self.onResolvedCallbacks = [];
+ self.onRejectedCallbacks = [];
function resolve(value){
if(self.status === 'pending'){ //只有pending状态下才可以改变状态
self.status = 'fulfilled';
self.value = value;
+ self.onResolvedCallbacks.forEach(item => item(value));
}
}
function reject(reson){
if(self.status === 'pending'){//只有pending状态下才可以改变状态
self.status = 'rejected';
self.reason = reson;
+ self.onRejectedCallbacks.forEach(item => item(value));
}
}
try{
executor(resolve,reject); // 此处为高阶函数,一个函数内传入其他函数,这就是高阶函数的一种
}catch(err){
reject(err);
}
}
Promise.prototype.then = function(onFulfilled,onRejected){
const self = this;
if(self.status === 'fulfilled'){
onFulfilled(self.value);
}
if(self.status === 'rejected'){
onRejected(self.reason);
}
+ if (self.status == 'pending') {
+ self.onResolvedCallbacks.push(function (value) {
+ try {
+ onFulfilled(value);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ self.onRejectedCallbacks.push(function (value) {
+ try {
+ onRejected(value);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ }
+ }
4、Promise/A+完整实现
resolvePromisefang方法解决了那些事情:
resolvePromise是什么?:这其实是官方Promise/A+的需求。因为你的then可以返回任何职,当然包括Promise对象,而如果是Promise对象,我们就需要将他拆解,直到它不是一个Promise对象,取其中的值。
function Promise(executor) {
let self = this;
self.status = "pending";
self.value = undefined;
self.onResolvedCallbacks = [];
self.onRejectedCallbacks = [];
function resolve(value) {
+ if (value instanceof Promise) {
+ return value.then(resolve, reject)
+ }
+ setTimeout(function () { // 异步执行所有的回调函数
if (self.status == 'pending') {
self.value = value;
self.status = 'resolved';
self.onResolvedCallbacks.forEach(item => item(value));
}
});
+ }
function reject(value) {
+ setTimeout(function () {
if (self.status == 'pending') {
self.value = value;
self.status = 'rejected';
self.onRejectedCallbacks.forEach(item => item(value));
}
});
+ }
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
+ function resolvePromise(promise2, x, resolve, reject) {
+ if (promise2 === x) {
+ return reject(new TypeError('循环引用'));
+ }
+ let then, called;
+ if (x != null && ((typeof x == 'object' || typeof x == 'function'))) {
+ try {
+ then = x.then;
+ if (typeof then == 'function') {
+ then.call(x, function (y) {
+ if (called)return;
+ called = true;
+ resolvePromise(promise2, y, resolve, reject);
+ }, function (r) {
+ if (called)return;
+ called = true;
+ reject(r);
+ });
+ } else {
+ resolve(x);
+ }
+ } catch (e) {
+ if (called)return;
+ called = true;
+ reject(e);
+ }
+ } else {
+ resolve(x);
+ }
+}
Promise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
+ onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : function (value) {
+ return value
+ };
+ onRejected = typeof onRejected == 'function' ? onRejected : function (value) {
+ throw value
+ };
+ let promise2;
if (self.status == 'resolved') {
+ promise2 = new Promise(function (resolve, reject) {
+ setTimeout(function () {
+ try {
+ let x = onFulfilled(self.value);
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
}
if (self.status == 'rejected') {
+ 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') {
+ promise2 = new Promise(function (resolve, reject) {
+ self.onResolvedCallbacks.push(function (value) {
+ try {
+ let x = onFulfilled(value);
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ self.onRejectedCallbacks.push(function (value) {
+ try {
+ let x = onRejected(value);
+ resolvePromise(promise2, x, resolve, reject);
+ } catch (e) {
+ reject(e);
+ }
+ });
+ });
+ }
+ return promise2;
}
四、Promise其他方法的实现
all:
Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
Promise.all=function(promises){
return new Promise((resolve,reject)=>{
promises=Array.from(promises);
const length=promises.length, results=[],_index=0;
if(length==0){
resolve(results)
return
}
promises.forEach((promise,index)=>{
Promise.resolve(promise).then(result=>{
results[index]=result;
if(length==++_index){
resolve(results)
}
}).catch(err=>{
reject(err)
})
})
})
}
race
const p = Promise.race([p1, p2, p3]);
上面代码中,只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数。
Promise.race=function(promises){
return new Promise((resolve,reject)=>{
promises=Array.from(promises);
if(promises.length==0){
resolve()
return
}
promises.forEach((promise,index)=>{
Promise.resolve(promise).then(result=>{
resolve(result)
}).catch(err=>{
reject(err)
})
})
})
}
finally
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
Promise.prototype.finally=function(onFinally){
var isFunction = typeof onFinally == "function";
return this.then(isFunction?(result)=>{
onFinally();
return result
}:onFinally,isFunction?(err)=>{
onFinally();
return Promise.reject(err)
}:onFinally);
}
resolve/reject
resolve:有时需要将现有对象转为 Promise 对象,Promise.resolve()方法就起到这个作用
reject:Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。
//resolve方法
Promise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
})
}
//reject方法
Promise.reject = function(val){
return new Promise((resolve,reject)=>{
reject(val)
})
}
function(){
- return 1+2
+ return a+b
}