Promise成为你们解决异步回调地狱问题的重要方法,理解它的原理和底层实现有助于咱们更加合理的使用。如下遵循PromiseA+规范实现了一个简单的Promise.jquery
实现分为六步:数组
明确promise有三个状态: pending fulfilled rejectedpromise
在new Promise时, excutor会当即执行bash
每一个promise上会有一个then方法, then方法中传递两个参数onFulfilled和onRejected异步
代码以下:测试
class Promise{
constructor(excutor){
this.status = 'pending'; // 默认是等待态
this.value = undefined;
this.reason = undefined;
let resolve = (value) => { // 调用resolve, 变成成功态
if (this.status === 'pending') {
this.status= 'fulfilled';
this.value = value;
}
};
let rejected = (reason) => { // 调用reject, 变成失败态
if (this.status === 'pending') {
this.status= 'rejected';
this.reason = reason;
}
};
excutor(resolve, rejected);
}
then(onFulfilled, onRejected){
console.log(this.status, 'status');
if (this.status === 'fulfilled') { // 变成成功态fulfilled时执行成功回调
onFulfilled(this.value);
}
if (this.status === 'rejected') { // 变成失败态rejected时执行失败回调
onFulfilled(this.reason);
}
}
}
复制代码
核心思路: 将成功和失败的回调放在数组中, 当状态改变时, 执行对应状态的事件ui
class Promise{
constructor(excutor){
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
this.onFulfilledCbs = []; // 存放成功状态的回调
this.onRejectedCbs = []; // 存放失败状态的回调
let resolve = (value) => {
if (this.status === 'pending') {
this.status= 'fulfilled';
this.value = value;
this.onFulfilledCbs.forEach(cb => cb()); // 依次执行成功回调
}
};
let rejected = (reason) => {
if (this.status === 'pending') {
this.status= 'rejected';
this.reason = reason;
this.onRejectedCbs.forEach(cb => cb()); // 依次执行失败回调
}
};
excutor(resolve, rejected)
}
then(onFulfilled, onRejected){
...
if (this.status === 'pending') { // 有异步逻辑时,状态为pending 将callback放在数组中
this.onFulfilledCbs.push(() => {
onFulfilled(this.value);
});
this.onRejectedCbs.push(() => {
onRejected(this.reason);
});
}
}
}
复制代码
思路: 返回一个新的promise实例. jquery中的方法也能链式调用, 是经过return this实现的.可是promise不能返回this, 由于, 一个promise的状态若是是fulfilled,就不能变成rejected.this
then的特色:spa
class Promise{
constructor(excutor){
...
try{ // 1. 在执行excutor时有可能抛出错误 直接捕获错误
excutor(resolve, reject);
}catch(err) {
reject(err);
}
}
// resolvePromise 判断当前promise返回结果x和promise2的关系
resolvePromise(promise2, x, resolve, reject) {
if((typeof x === 'object' && x !== null) || typeof x === 'function'){
try{ // 取then方法时 有可能报错
let then = x.then;
if (typeof then === 'function') { // 2.2.2 返回一个promise 执行promise
then.call(x, (y) => {
resolve(y);
}, (r) => {
reject(r);
});
} else { // 2.2.3 返回一个带有then属性的普通对象 {then: ...}
resolve(x);
}
}catch(e){
reject(e);
}
} else {// 2.2.1 返回一个常量
resolve(x);
}
}
then(onFulfilled, onRejected){
// 2.实现then的链式调用(jq)
let promise2 = new Promise((resolve, reject) => { // 2.1 返回一个新的promise
if (this.status === 'fulfilled') {
try{ // 若是方法执行报错 直接抛出错误
let x = onFulfilled(this.value); // 2.2 处理前一个promise中onFulfilled的不一样返回结果和下一个promise的关系: 普通值/promise
this.resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}
if (this.status === 'rejected') {
try{
let x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
}
if (this.status === 'pending') {
this.onFulfilledCbs.push(() => {
try{
let x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
});
this.onRejectedCbs.push(() => {
try{
let x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
});
}
});
return promise2;
}
}
复制代码
class Promise{
...
resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) { // 4.1 return的值不能为promise2(本身等待本身) 不然会报循环引用错误
return reject(new Error('循环引用'));
}
let called; // 4.4 定义called 避免成功失败只能调用一个
if((typeof x === 'object' && x !== null) || typeof x === 'function'){
try{
let then = x.then;
if (typeof then === 'function') {
then.call(x, (y) => {
if (called) return; // 成功和失败只会掉一个
called = true;
this.resolvePromise(promise2, y, resolve, reject); // 4.3 若是y是一个promise 进行递归解析
}, (r) => {
if (called) return; // 若是掉过成功
called = true;
reject(r);
});
} else {
if (called) return;
called = true;
resolve(x);
}
}catch(e){
if (called) return;
called = true;
reject(e);
}
} else {
if (called) return;
called = true;
resolve(x);
}
}
then(onFulfilled, onRejected){
let promise2 = new Promise((resolve, reject) => {
if (this.status === 'fulfilled') {
setTimeout(() => { // 4.2 若是不加setTimeout会致使promise2为undefined-->then方法都是异步的
try{
let x = onFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject); // 初始化promise2未完成, 为undefined
}catch(e){
reject(e);
}
});
}
if (this.status === 'rejected') {
setTimeout(() => {
try{
let x = onRejected(this.reason);
this.resolvePromise(promise2, x, resolve, reject);
}catch(e){
reject(e);
}
});
}
....
});
return promise2;
}
}
module.exports = Promise;
复制代码
思路: 若是promise执行resolve, 就将resolve中的值经过onFULfilled传递; 若是promise执行reject, 就将reject中的值经过onRejected传递插件
then(onFulfilled, onRejected){
// 5 穿透实现
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (data) => {
return data;
};
onRejected = typeof onRejected === 'function' ? onRejected : (err) => {
throw err;
};
...
}
复制代码
在promise A+规范中提出, 经过promises-aplus-tests插件对本身写的promise进行检验, 可是这个插件使用前须要经过promise.defer将promise的属性挂载在defer上, 代码以下:
Promise.deferred = Promise.defer = () => {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
复制代码
下面就能够经过promises-aplus-tests插件对本身写的promise进行检验了: