Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最先提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。 @阮老师编程
promise
的几种用法:new Promise((resolve, reject) => resolve()).then(() => {
console.log('success');
}, () => {
console.log('err')
})
复制代码
若是没有指定reject函数,最后就会执行catch函数
new Promise((resolve, reject) => {
reject('err');
})
.then()
.catch(e => {
console.log(e); // => Error: err
})
复制代码
Promise.resolve('hahaha').then(data => {
console.log(data); // => 'hahaha'
})
复制代码
Promise.reject('hahaha').then(data => {
console.log(data); // => 'hahaha'
})
复制代码
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise1');
}, 1500);
})
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('promise2');
}, 2000);
})
Promise.all([promise1, promise2]).then(data => {
console.log(data); // => ["promise1", "promise2"]
})
复制代码
咱们先来简单的用一下promise
:数组
console.log(1)
new Promise(() => {
console.log(2)
});
console.log(3)
复制代码
由于咱们都知道promise
是异步的,因此按理会依次输出 1,3,2
而后咱们运行以后发现 它依次输出的是 1,2,3
当咱们使用then
的时候:promise
console.log(1)
Promise.resolve().then(() => {
console.log(2);
})
console.log(3)
复制代码
再次运行,发现结果和咱们以前想的是同样的,会依次输出 1,3,2
这是由于promise
的callback
是当即执行的,只有then
方法是异步的bash
A promise must be in one of three states: pending, fulfilled, or rejected.异步
pending
的时候
fulfilled
的时候
value
(成功以后的值)rejected
的时候
reason
(失败的缘由)class Promise {
constructor(executor) {
// 每个promise实例都有本身的三个状态,咱们用一个变量来保存当前的状态
this.status = 'pending';
// 用来保存执行成功时的值
this.value;
// 用来保存执行失败时的缘由
this.reason;
// 用来将当前状态改变为成功态的方法
let resolve = val => {
// 只有当前状态是`pending` 才能够改变状态和值
if (this.status === 'pending') {
this.value = val;
this.status = 'fulfilled';
}
}
// 用来将当前状态改变为失败态的方法
let reject = reason => {
// 只有当前状态是`pending` 才能够改变状态和值
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
}
}
// 执行executor可能会直接抛出异常,咱们用try catch包起来
try {
executor(resolve, reject);
} catch (e) {
// 若是抛出异常,咱们直接将状态改成失败态
reject(e);
}
}
}
复制代码
then
方法一个promise必须提供一个
then
方法去获取当前的或最终的value or reason异步编程
promise的
then
方法有两个参数,分别是成功时执行的方法onFulfilled
和失败时执行的方法onRejected
函数
onFulfilled
和 onRejected
都是可选的参数
onFulfilled
是一个function
promise
的状态变成fulfilled
以后被调用,将promise的value
(成功以后的值)做为他的第一个参数fulfilled
以前不能调用它onRejected
是一个function
promise
的状态变成rejected
以后被调用,将promise的reason
(失败的缘由)做为他的第一个参数rejected
以前不能调用它promise.then(onFulfilled, onRejected)
复制代码
class Promise {
constructor(executor) {...}
then(onFulfilled, onRejected) {
// 若是当前状态是成功态,咱们就执行成功的回调,并将存起来的成功的值value传过去
if (this.status === 'fulfilled') {
onFulfilled(this.value);
}
// 若是当前状态是失败态,咱们就执行失败的回调,并将存起来的失败缘由reason传过去
if (this.status === 'rejected') {
onRejected(this.reason);
}
}
}
复制代码
好了,咱们如今已经能够简单的测试一下了测试
new Promise((resolve, reject) => {
resolve('完美');
}).then(data => {
console.log(data); // => 完美
})
复制代码
完美,可是那么问题来了,若是咱们的 resolve
或 reject
是异步的呢?ui
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('完美');
}, 1000);
}).then(data => {
console.log(data);
}, err => {
console.log(err);
})
复制代码
运行以后咱们发现什么都没有输出,onFulfilled
和 onRejected
都没有打印东西,那说明他们都没有执行,let me think think...this
这是由于若是咱们的 resolve
或 reject
是异步的,当咱们的then
执行的时候,状态尚未改变,仍是pending
状态,因此固然什么都不会执行。咱们能够先把 onFulfilled
和 onRejected
存起来,等状态改变的时候依次执行对应的callback。A: 这难道是?B: 没错,这就是订阅发布模式。下面咱们来改写一下:
class Promise {
constructor(executor) {
this.status = 'pending';
this.value;
this.reason;
// 用来保存成功时执行的回调函数
this.onSuccessCallback = [];
// 用来保存失败时执行的回调函数
this.onErrorCallback = [];
let resolve = val => {
if (this.status === 'pending') {
this.value = val;
this.status = 'fulfilled';
// 状态改变时 依次执行成功的回调
this.onSuccessCallback.forEach(fn => fn());
}
}
let reject = reason => {
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
// 状态改变时 依次执行失败的回调
this.onErrorCallback.forEach(fn => fn());
}
}
// 执行executor可能会直接抛出异常,咱们用try catch包起来
try {
executor(resolve, reject);
} catch (e) {
// 若是抛出异常,咱们直接将状态改成失败态
reject(e);
}
}
then(onFulfilled, onRejected) {
if (this.status === 'fulfilled') {
onFulfilled(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
if (this.status === 'pending') {
// 将成功回调和失败回调都存起来,等待状态改变,再依次执行对应的方法
this.onSuccessCallback.push(() => {
onFulfilled(this.value);
});
this.onErrorCallback.push(() => {
onRejected(this.reason);
});
}
}
}
复制代码
onFulfilled
和 onRejected
都是异步调用(微任务)
onFulfilled
和 onRejected
必须做为一个函数被执行
then
方法必须返回一个promise
promise2 = promise1.then(onFulfilled, onRejected)
复制代码
onFulFilled
or onRejected
返回了一个值x
,运行promise解析程序onFulfilled
or onRejected
抛出了一个异常e
,promise2
的状态必须是rejected
,并将e
做为onRejected
的参数onFulfilled
不是一个function
而且promise1
是fulfilled
,promise2
必须也是fulfilled
而且使用和promise1
相同的value
onRejected
不是一个function
而且promise1
是rejected
,promise2
必须也是rejected
而且使用和promise1
相同的reason
咱们用promise的时候常常promise.then().then().then() ...
这种写法叫链式调用,那怎么样才能继续调用then
方法呢,规范规定then
方法必须返回一个promise实例,这样就能够实现链式调用了
class Promise {
contructor() {...}
then(onFulfilled, onRejected) {
// 若是onFulfilled和onFulfilled 不是一个函数,咱们给一个默认值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
// 咱们将全部东西都包到一个promise实例中,最后返回这个实例,这样就能够实现链式调用
let promise2;
// `onFulfilled` 和 `onRejected`都是异步调用,咱们先用一个定时器实现异步调用
promise2 = new Promise((resolve, reject) => {
if (this.status === 'fulfilled') {
setTimeout(() => {
try {
// 有一个返回值x,运行解析函数resolvePromise
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === 'rejected') {
setTimeout(() => {
try {
// 有一个返回值x,运行解析函数resolvePromise
let x = onRejected(this.reason);;
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === 'pending') {
// 将成功回调和失败回调都存起来,等待状态改变,再依次执行对应的方法
this.onSuccessCallback.push(() => {
setTimeout(() => {
try {
// 有一个返回值x,运行解析函数resolvePromise
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
});
this.onErrorCallback.push(() => {
setTimeout(() => {
try {
// 有一个返回值x,运行解析函数resolvePromise
let x = onRejected(this.reason);;
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
}
复制代码
这里可能就会有疑惑了,若是有一个返回值x
就运行promise解析程序resolvePromise
,这是什么鬼?
咱们先来看看规范:
promise的解析程序是将
promise2
和x
做为参数的函数
若是promise2
和x
是一个promise,那么抛出一个TypeError
若是x
是一个object
或function
then
存储x.then
x.then
会抛出异常e
,调用promise的reject
,并将e
做为它的参数then
是一个function
,使用call
把它的this
指向x
,它的第一个参数是resolvePromise
,第二个参数是rejectPromise
:
resolvePromise
被y
值调用的时候,继续执行解析程序rejectPromise
执行的时候,调用promise的reject
并将将失败缘由r
做为它的参数then
不是一个object
or function
,调用promise的resolve
并将x
做为它的参数若是x
不是一个object
or function
,调用promise的resolve
并将x
做为它的参数
总结下来就两点:
若是promise2
和x
相等,就抛出一个TypeError
,咱们先来看一下
let p = new Promise((resolve, reject) => {
// 返回当前promise实例
return p;
});
p.then(data => {
console.log(data);
}, err => {
console.log(err);
});
复制代码
运行上面代码,咱们会发现promise抛出了一个异常,他告诉咱们TypeError: Chaining cycle detected for promise
,这是由于p
的成功仍是失败取决于本身,本身再等待本身的执行结果,因此他既不会成功也不会失败
onFulFilled
or onRejected
返回了一个值x
,运行promise解析程序resolvePromise
返回值x
有多是一个常量,对象,也有多是一个promise,这个程序的做用就是若是 x
是一个promise,那就将 x
一直解析到常量位置
let p = new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
resolve(1111);
}))
})
复制代码
let resolvePromise = (promise2, x, resolve, reject) => {
// 若是promise2和x相等,就抛出一个类型错误
if (promise2 === x) {
return reject(new TypeError('错了'));
}
// 只容许调用一次resolvePromise
let called;
// 若是x不是一个常量继续解析
if (x !== null && (typeof x === 'function' || typeof x === 'object')) {
// 调用x.then的时候可能会报错,由于咱们有可能和别人的Promise库混用
try {
let then = x.then;
// 若是then是一个函数,证实x是一个promise,继续解析
if (typeof then === 'function') {
then.call(x, y => {
if (called) {
return;
} else {
called = true;
}
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) {
return;
} else {
called = true;
}
reject(r);
})
} else {
// 说明x多是一个普通对象,不是一个promise
resolve(x);
}
} catch (e) {
if (called) {
return;
} else {
called = true;
}
reject(e);
}
} else {
// 说明x是一个常量,直接执行resolve
resolve(x);
}
}
复制代码
接下来咱们来实现Promise.resolve
Promise.reject
Promise.all
class Promise {
contructor {...}
then() {...}
// 其实Promise.reject和Promise.reject很是简单
static resolve(value) {
return new Promise((resolve) => {
resolve(value);
})
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
// all方法
static all(promises) {
return new Promise((resolve, reject) => {
// 用来保存结果
let arr = [];
let index = 0;
const saveData = (i, data) => {
arr[i] = data;
if (++index === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
saveData(i, data);
}, reject)
}
})
}
}
复制代码
好了,接下来咱们来一个完整版的promise
class Promise {
contructor() {
this.status = 'pending';
this.value;
this.reason;
// 用来保存成功时执行的回调函数
this.onSuccessCallback = [];
// 用来保存失败时执行的回调函数
this.onErrorCallback = [];
let resolve = val => {
if (this.status === 'pending') {
this.value = val;
this.status = 'fulfilled';
// 状态改变时 依次执行成功的回调
this.onSuccessCallback.forEach(fn => fn());
}
}
let reject = reason => {
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
// 状态改变时 依次执行失败的回调
this.onErrorCallback.forEach(fn => fn());
}
}
// 执行executor可能会直接抛出异常,咱们用try catch包起来
try {
executor(resolve, reject);
} catch (e) {
// 若是抛出异常,咱们直接将状态改成失败态
reject(e);
}
}
static resolve(value) {
return new Promise((resolve) => {
resolve(value);
})
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
})
}
static all(promises) {
return new Promise((resolve, reject) => {
// 用来保存结果
let arr = [];
let index = 0;
const saveData = (i, data) => {
arr[i] = data;
if (++index === promises.length) {
resolve(arr);
}
}
for (let i = 0; i < promises.length; i++) {
promises[i].then(data => {
saveData(i, data);
}, reject)
}
})
}
then(onFulfilled, onRejected) {
// 若是onFulfilled和onFulfilled 不是一个函数,咱们给一个默认值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
// 咱们将全部东西都包到一个promise实例中,最后返回这个实例,这样就能够实现链式调用
let promise2;
// `onFulfilled` 和 `onRejected`都是异步调用,咱们先用一个定时器实现异步调用
promise2 = new Promise((resolve, reject) => {
if (this.status === 'fulfilled') {
setTimeout(() => {
try {
// 有一个返回值x,运行解析函数resolvePromise
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === 'rejected') {
setTimeout(() => {
try {
// 有一个返回值x,运行解析函数resolvePromise
let x = onRejected(this.reason);;
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === 'pending') {
// 将成功回调和失败回调都存起来,等待状态改变,再依次执行对应的方法
this.onSuccessCallback.push(() => {
setTimeout(() => {
try {
// 有一个返回值x,运行解析函数resolvePromise
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
});
this.onErrorCallback.push(() => {
setTimeout(() => {
try {
// 有一个返回值x,运行解析函数resolvePromise
let x = onRejected(this.reason);;
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
}
let resolvePromise = (promise2, x, resolve, reject) => {
// 若是promise2和x相等,就抛出一个类型错误
if (promise2 === x) {
return reject(new TypeError('错了'));
}
// 只容许调用一次resolvePromise
let called;
// 若是x不是一个常量继续解析
if (x !== null && (typeof x === 'function' || typeof x === 'object')) {
// 调用x.then的时候可能会报错,由于咱们有可能和别人的Promise库混用
try {
let then = x.then;
// 若是then是一个函数,证实x是一个promise,继续解析
if (typeof then === 'function') {
then.call(x, y => {
if (called) {
return;
} else {
called = true;
}
resolvePromise(promise2, y, resolve, reject);
}, r => {
if (called) {
return;
} else {
called = true;
}
reject(r);
})
} else {
// 说明x多是一个普通对象,不是一个promise
resolve(x);
}
} catch (e) {
if (called) {
return;
} else {
called = true;
}
reject(e);
}
} else {
// 说明x是一个常量,直接执行resolve
resolve(x);
}
}
复制代码