Promise你们必定都不陌生了,JavaScript异步流程从最初的Callback,到Promise,到Generator,再到目前使用最多的Async/Await(若是对于这些不熟悉的能够参考我另外一篇文章《JavaScript异步编程》),这不只仅是技术实现的发展,更是思想上对于如何控制异步的递进。Promise做为后续方案的基础,是重中之重,也是面试时候最常被问到的。git
今天咱们就一块儿从0到1实现一个基于A+规范的Promise,过程当中也会对Promise的异常处理,以及是否可手动终止作一些讨论,最后会对咱们实现的Promise作单元测试。完整的代码已经上传到github,想直接看代码的能够点这里。github
虽然已经有不少带你实现Promise类的文章了,但每一个人理解的程度不同,也许不一样的文章能够带给你不一样的思考呢,那咱们就开始吧。面试
new Promise()时接收一个executor函数做为参数,该函数会当即执行,函数中有两个参数,它们也是函数,分别是resolve和reject,函数同步执行必定要放在try...catch中,不然没法进行错误捕获。算法
MyPromise.js编程
function MyPromise(executor) {
function resolve(value) {
}
function reject(reason) {
}
try {
executor(resolve, reject);
} catch (reason) {
reject(reason);
}
}
module.exports = MyPromise;
复制代码
resolve()接收Promise成功值value,reject接收Promise失败缘由reason。segmentfault
test.js数组
let MyPromise = require('./MyPromise.js');
let promise = new MyPromise(function(resolve, reject) {
resolve(123);
})
复制代码
目前实现存在的问题:promise
pending
,成功状态为 fulfilled
,失败状态为 rejected
。只能从 pending
-> fulfilled
,或者从 pending
-> rejected
,而且状态一旦转变,就永远不会再变了。因此,咱们须要为Promise添加一个状态流转的机制。bash
MyPromise.js微信
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function MyPromise(executor) {
let self = this;
self.state = PENDING;
function resolve(value) {
if (self.state === PENDING) {
self.state = FULFILLED;
}
}
function reject(reason) {
if (self.state === PENDING) {
self.state = REJECTED;
}
}
try {
executor(resolve, reject);
} catch (reason) {
reject(reason);
}
}
module.exports = MyPromise;
复制代码
test.js
let MyPromise = require('./MyPromise.js');
let promise = new MyPromise(function(resolve, reject) {
resolve(123);
});
promise.then(function(value) {
console.log('value', value);
}, function(reason) {
console.log('reason', reason);
})
复制代码
then
方法Promise拥有一个then
方法,接收两个函数 onFulfilled
和 onRejected
,分别做为Promise成功和失败的回调。因此,在then
方法中咱们须要对状态state
进行判断,若是是fulfilled
,则执行onFulfilled(value)
方法,若是是rejected
,则执行onRejected(reason)
方法。
因为成功值value
和失败缘由reason
是由用户在executor
中经过resolve(value)
和 reject(reason)
传入的,因此咱们须要有一个全局的value
和reason
供后续方法获取。
MyPromise.js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function MyPromise(executor) {
let self = this;
self.state = PENDING;
self.value = null;
self.reason = null;
function resolve(value) {
if (self.state === PENDING) {
self.state = FULFILLED;
self.value = value;
}
}
function reject(reason) {
if (self.state === PENDING) {
self.state = REJECTED;
self.reason = reason;
}
}
try {
executor(resolve, reject);
} catch (reason) {
reject(reason);
}
}
MyPromise.prototype.then = function(onFuifilled, onRejected) {
let self = this;
if (self.state === FULFILLED) {
onFuifilled(self.value);
}
if (self.state === REJECTED) {
onRejected(self.reason);
}
};
module.exports = MyPromise;
复制代码
目前实现存在的问题:
resolve()
没有问题,但若是是异步调用,好比放到setTimeout
中,由于目前的代码在调用then()
方法时,state
还是pending
状态,当timer到时候调用resolve()
把state
修改成fulfilled
状态,可是onFulfilled()
函数已经没有时机调用了。针对上述问题,进行以下修改:
MyPromise.js
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function MyPromise(executor) {
let self = this;
self.state = PENDING;
self.value = null;
self.reason = null;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
function resolve(value) {
if (self.state === PENDING) {
self.state = FULFILLED;
self.value = value;
self.onFulfilledCallbacks.forEach(function(fulfilledCallback) {
fulfilledCallback();
});
}
}
function reject(reason) {
if (self.state === PENDING) {
self.state = REJECTED;
self.reason = reason;
self.onRejectedCallbacks.forEach(function(rejectedCallback) {
rejectedCallback();
});
}
}
try {
executor(resolve, reject);
} catch (reason) {
reject(reason);
}
}
MyPromise.prototype.then = function(onFuifilled, onRejected) {
let self = this;
if (self.state === PENDING) {
self.onFulfilledCallbacks.push(() => {
onFuifilled(self.value);
});
self.onRejectedCallbacks.push(() => {
onRejected(self.reason);
});
}
if (self.state === FULFILLED) {
onFuifilled(self.value);
}
if (self.state === REJECTED) {
onRejected(self.reason);
}
};
module.exports = MyPromise;
复制代码
咱们添加了两个回调函数数组onFulfilledCallbacks
和onRejectedCallbacks
,用来存储then()
方法中传入的成功和失败回调。而后,当用户调用resolve()
或reject()
的时候,修改state
状态,并从相应的回调数组中依次取出回调函数执行。
同时,经过这种方式咱们也实现了能够注册多个then()
函数,而且在成功或者失败时按照注册顺序依次执行。
test.js
let MyPromise = require('./MyPromise.js');
let promise = new MyPromise(function(resolve, reject) {
setTimeout(function() {
resolve(123);
}, 1000);
});
promise.then(function(value) {
console.log('value1', value);
}, function(reason) {
console.log('reason1', reason);
});
promise.then(function(value) {
console.log('value2', value);
}, function(reason) {
console.log('reason2', reason);
});
复制代码
读过PromiseA+规范的同窗确定知道,then()
方法返回的还是一个Promise,而且返回Promise的resolve
的值是上一个Promise的onFulfilled()
函数或onRejected()
函数的返回值。若是在上一个Promise的then()
方法回调函数的执行过程当中发生了错误,那么会将其捕获到,并做为返回的Promise的onRejected
函数的参数传入。好比:
let promise = new Promise((resolve, reject) => {
resolve(123);
});
promise.then((value) => {
console.log('value1', value);
return 456;
}).then((value) => {
console.log('value2', value);
});
let promise = new Promise((resolve, reject) => {
resolve(123);
});
复制代码
打印结果为:
value1 123
value2 456
let promise = new Promise((resolve, reject) => {
resolve(123);
});
promise.then((value) => {
console.log('value1', value);
a.b = 2; // 这里存在语法错误
return 456;
}).then((value) => {
console.log('value2', value);
}, (reason) => {
console.log('reason2', reason);
});
复制代码
打印结果为:
value1 123
reason2 ReferenceError: a is not defined
能够看到,then()
方法回调函数若是发生错误,会被捕获到,那么then()
返回的Promise会自动变为onRejected
,执行onRejected()
回调函数。
let promise = new Promise((resolve, reject) => {
reject(123);
});
promise.then((value) => {
console.log('value1', value);
return 456;
}, (reason) => {
console.log('reason1', reason);
return 456;
}).then((value) => {
console.log('value2', value);
}, (reason) => {
console.log('reason2', reason);
});
复制代码
打印结果为:
reason1 123
value2 456
好啦,接下来咱们就去实现then()
方法依然返回一个Promise。
MyPromise.js
MyPromise.prototype.then = function(onFuifilled, onRejected) {
let self = this;
let promise2 = null;
promise2 = new MyPromise((resolve, reject) => {
if (self.state === PENDING) {
self.onFulfilledCallbacks.push(() => {
try {
let x = onFuifilled(self.value);
self.resolvePromise(promise2, x, resolve, reject);
} catch(reason) {
reject(reason);
}
});
self.onRejectedCallbacks.push(() => {
try {
let x = onRejected(self.reason);
self.resolvePromise(promise2, x, resolve, reject);
} catch(reason) {
reject(reason);
}
});
}
if (self.state === FULFILLED) {
try {
let x = onFuifilled(self.value);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}
if (self.state === REJECTED) {
try {
let x = onRejected(self.reason);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}
});
return promise2;
};
复制代码
能够看到,咱们新增了一个promise2
做为then()
方法的返回值。经过let x = onFuifilled(self.value)
或者 let x = onRejected(self.reason)
拿到then()
方法回调函数的返回值,而后调用self.resolvePromise(promise2, x, resolve, reject)
,将新增的promise2
、x
、promise2
的resolve
和reject
传入到resolvePromise()
中。
因此,下面咱们重点看一下resolvePromise()
方法。
MyPromise.js
MyPromise.prototype.resolvePromise = function(promise2, x, resolve, reject) {
let self = this;
let called = false; // called 防止屡次调用
if (promise2 === x) {
return reject(new TypeError('循环引用'));
}
if (x !== null && (Object.prototype.toString.call(x) === '[object Object]' || Object.prototype.toString.call(x) === '[object Function]')) {
// x是对象或者函数
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, (y) => {
// 别人的Promise的then方法可能设置了getter等,使用called防止屡次调用then方法
if (called) return ;
called = true;
// 成功值y有可能仍是promise或者是具备then方法等,再次resolvePromise,直到成功值为基本类型或者非thenable
self.resolvePromise(promise2, y, resolve, reject);
}, (reason) => {
if (called) return ;
called = true;
reject(reason);
});
} else {
if (called) return ;
called = true;
resolve(x);
}
} catch (reason) {
if (called) return ;
called = true;
reject(reason);
}
} else {
// x是普通值,直接resolve
resolve(x);
}
};
复制代码
resolvePromise()
是用来解析then()
回调函数中返回的还是一个Promise
,这个Promise
有多是咱们本身的,有多是别的库实现的,也有多是一个具备then()
方法的对象,因此这里靠resolvePromise()
来实现统一处理。
下面是翻译自PromiseA+规范关于resolvePromise()
的要求:
Promise 解决过程
Promise 解决过程是一个抽象的操做,其需输入一个 promise 和一个值,咱们表示为 [[Resolve]](promise, x),若是 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;不然其用 x 的值来执行 promise 。
这种 thenable 的特性使得 Promise 的实现更具备通用性:只要其暴露出一个遵循 Promise/A+ 协议的 then 方法便可;这同时也使遵循 Promise/A+ 规范的实现能够与那些不太规范但可用的实现能良好共存。
运行 [[Resolve]](promise, x) 需遵循如下步骤:
x 与 promise 相等
若是 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
x 为 Promise
若是 x 为 Promise ,则使 promise 接受 x 的状态:
x 为对象或函数 若是 x 为对象或者函数:
若是一个 promise 被一个循环的 thenable 链中的对象解决,而 [[Resolve]](promise, thenable) 的递归性质又使得其被再次调用,根据上述的算法将会陷入无限递归之中。算法虽不强制要求,但也鼓励施者检测这样的递归是否存在,若检测到存在则以一个可识别的 TypeError 为据因来拒绝 promise。
参考上述规范,结合代码中的注释,相信你们能够理解resolvePromise()
的做用了。
测试:
test.js
let MyPromise = require('./MyPromise.js');
let promise = new MyPromise(function(resolve, reject) {
setTimeout(function() {
resolve(123);
}, 1000);
});
promise.then((value) => {
console.log('value1', value);
return new MyPromise((resolve, reject) => {
resolve(456);
}).then((value) => {
return new MyPromise((resolve, reject) => {
resolve(789);
})
});
}, (reason) => {
console.log('reason1', reason);
}).then((value) => {
console.log('value2', value);
}, (reason) => {
console.log('reason2', reason);
});
复制代码
打印结果:
value1 123
value2 789
then()
方法的回调函数老是异步调用官方Promise
实现的回调函数老是异步调用的:
console.log('start');
let promise = new Promise((resolve, reject) => {
console.log('step-');
resolve(123);
});
promise.then((value) => {
console.log('step--');
console.log('value', value);
});
console.log('end');
复制代码
打印结果:
start
step-
end
step--
value1 123
Promise属于微任务,这里咱们为了方便用宏任务setTiemout
来代替实现异步,具体关于宏任务、微任务以及Event Loop能够参考个人另外一篇文章带你完全弄懂Event Loop。
MyPromise.js
MyPromise.prototype.then = function(onFuifilled, onRejected) {
let self = this;
let promise2 = null;
promise2 = new MyPromise((resolve, reject) => {
if (self.state === PENDING) {
self.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFuifilled(self.value);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}, 0);
});
self.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(self.reason);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}, 0);
});
}
if (self.state === FULFILLED) {
setTimeout(() => {
try {
let x = onFuifilled(self.value);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}, 0);
}
if (self.state === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(self.reason);
self.resolvePromise(promise2, x, resolve, reject);
} catch (reason) {
reject(reason);
}
}, 0);
}
});
return promise2;
};
复制代码
测试:
test.js
let MyPromise = require('./MyPromise.js');
console.log('start');
let promise = new MyPromise((resolve, reject) => {
console.log('step-');
setTimeout(() => {
resolve(123);
}, 1000);
});
promise.then((value) => {
console.log('step--');
console.log('value', value);
});
console.log('end');
复制代码
打印结果:
start
step-
end
step--
value1 123
通过以上步骤,一个最基本的Promise就已经实现完了,下面咱们会实现一些不在PromiseA+规范的扩展方法。
catch()
方法then()
方法的onFulfilled
和onRejected
回调函数都不是必传项,若是不传,那么咱们就没法接收reject(reason)
中的错误,这时咱们能够经过链式调用catch()
方法用来接收错误。举例:
let promise = new Promise((resolve, reject) => {
reject('has error');
});
promise.then((value) => {
console.log('value', value);
}).catch((reason) => {
console.log('reason', reason);
});
复制代码
打印结果:
reason has error
不只如此,catch()
能够做为Promise链式调用的最后一步,前面Promise发生的错误会冒泡到最后一个catch()
中,从而捕获异常。举例:
let promise = new Promise((resolve, reject) => {
resolve(123);
});
promise.then((value) => {
console.log('value', value);
return new Promise((resolve, reject) => {
reject('has error1');
});
}).then((value) => {
console.log('value', value);
return new Promise((resolve, reject) => {
reject('has error2');
});
}).catch((reason) => {
console.log('reason', reason);
});
复制代码
打印结果:
value 123
reason has error1
那么catch()
方法究竟是如何实现的呢?
答案就是在Promise的实现中,onFulfilled
和onRejected
函数是有默认值的:
MyPromise.js
MyPromise.prototype.then = function(onFuifilled, onRejected) {
onFuifilled = typeof onFuifilled === 'function' ? onFuifilled : value => {return value;};
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};
};
MyPromise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
复制代码
能够看到,onRejected
的默认值是把错误reason
经过throw
抛出去。因为咱们对于同步代码的执行都是在try...catch
中的,因此若是Promise发生了错误,若是没传onRejected
,默认的函数会把错误reason
抛出,而后会被promise2捕捉到,做为reject(reason)
决议。
catch()
实现就是调用this.then(null, onRejected)
,因为promise2
被reject
,因此会执行onRejected
回调,因而就捕捉到了第一个promise的错误。
总结来讲,then()
方法中不传onRejected
回调,Promise
内部会默认帮你写一个函数做为回调,做用就是throw
抛出reject
或者try...catch
到的错误,而后错误reason
会被promise2
做为reject(reason)
进行决议,因而会被下一个then()
方法的onRejected
回调函数调用,而catch
只是写了一个特殊的then(null, onRejected)
而已。
因此,咱们在写Promise
的链式调用的时候,在then()
中能够不传onRejected
回调,只须要在链式调用的最末尾加一个catch()
就能够了,这样在该链条中的Promise
发生的错误都会被最后的catch
捕获到。
举例1:
let promise = new Promise((resolve, reject) => {
reject(123);
});
promise.then((value) => {
// 注意,不会走这里,由于第一个promise是被reject的
console.log('value1', value);
return new Promise((resolve, reject) => {
reject('has error1');
});
}).then((value) => {
console.log('value2', value);
return new Promise((resolve, reject) => {
reject('has error2');
});
}, (reason) => {
// 注意,这个then有onRejected回调
console.log('reason2', reason);
}).catch((reason) => {
// 错误在上一个then就被捕获了,因此不会走到这里
console.log('reason3', reason);
});
复制代码
打印结果:
reason2 123
举例2:
let promise = new Promise((resolve, reject) => {
reject(123);
});
promise.then((value) => {
console.log('value1', value);
return new Promise((resolve, reject) => {
reject('has error1');
});
}).then((value) => {
console.log('value2', value);
return new Promise((resolve, reject) => {
reject('has error2');
});
}).catch((reason) => {
// 因为链条中的then都没有onRejected回调,因此会一直被冒泡到最后的catch这里
console.log('reason3', reason);
});
复制代码
catch
和then
同样都是返回一个新的Promise
。有的同窗可能会有疑问,若是catch
中的回调执行也发生错误该怎么办呢,这个咱们后续在Promise异常处理中再作讨论。
打印结果:
reason3 123
finally
方法finally
是某些库对Promise
实现的一个扩展方法,不管是resolve
仍是reject
,都会走finally
方法。
MyPromise.js
MyPromise.prototype.finally = function(fn) {
return this.then(value => {
fn();
return value;
}, reason => {
fn();
throw reason;
});
};
复制代码
done
方法done
方法做为Promise
链式调用的最后一步,用来向全局抛出没有被Promise
内部捕获的错误,而且再也不返回一个Promise
。通常用来结束一个Promise
链。
MyPromise.js
MyPromise.prototype.done = function() {
this.catch(reason => {
console.log('done', reason);
throw reason;
});
};
复制代码
Promise.all
方法Promise.all()
接收一个包含多个Promise
的数组,当全部Promise
均为fulfilled
状态时,返回一个结果数组,数组中结果的顺序和传入的Promise
顺序一一对应。若是有一个Promise
为rejected
状态,则整个Promise.all
为rejected
。
MyPromise.js
MyPromise.all = function(promiseArr) {
return new MyPromise((resolve, reject) => {
let result = [];
promiseArr.forEach((promise, index) => {
promise.then((value) => {
result[index] = value;
if (result.length === promiseArr.length) {
resolve(result);
}
}, reject);
});
});
};
复制代码
test.js
let MyPromise = require('./MyPromise.js');
let promise1 = new MyPromise((resolve, reject) => {
console.log('aaaa');
setTimeout(() => {
resolve(1111);
console.log(1111);
}, 1000);
});
let promise2 = new MyPromise((resolve, reject) => {
console.log('bbbb');
setTimeout(() => {
reject(2222);
console.log(2222);
}, 2000);
});
let promise3 = new MyPromise((resolve, reject) => {
console.log('cccc');
setTimeout(() => {
resolve(3333);
console.log(3333);
}, 3000);
});
Promise.all([promise1, promise2, promise3]).then((value) => {
console.log('all value', value);
}, (reason) => {
console.log('all reason', reason);
})
复制代码
打印结果:
aaaa
bbbb
cccc
1111
2222
all reason 2222
3333
Promise.race
方法Promise.race()
接收一个包含多个Promise
的数组,当有一个Promise
为fulfilled
状态时,整个大的Promise
为onfulfilled
,并执行onFulfilled
回调函数。若是有一个Promise
为rejected
状态,则整个Promise.race
为rejected
。
MyPromise.js
MyPromise.race = function(promiseArr) {
return new MyPromise((resolve, reject) => {
promiseArr.forEach(promise => {
promise.then((value) => {
resolve(value);
}, reject);
});
});
};
复制代码
test.js
let MyPromise = require('./MyPromise.js');
let promise1 = new MyPromise((resolve, reject) => {
console.log('aaaa');
setTimeout(() => {
resolve(1111);
console.log(1111);
}, 1000);
});
let promise2 = new MyPromise((resolve, reject) => {
console.log('bbbb');
setTimeout(() => {
reject(2222);
console.log(2222);
}, 2000);
});
let promise3 = new MyPromise((resolve, reject) => {
console.log('cccc');
setTimeout(() => {
resolve(3333);
console.log(3333);
}, 3000);
});
Promise.race([promise1, promise2, promise3]).then((value) => {
console.log('all value', value);
}, (reason) => {
console.log('all reason', reason);
})
复制代码
打印结果:
aaaa
bbbb
cccc
1111
all reason 1111
2222
3333
Promise.resolve
方法Promise.resolve
用来生成一个fulfilled
完成态的Promise
,通常放在整个Promise
链的开头,用来开始一个Promise
链。
MyPromise.js
MyPromise.resolve = function(value) {
let promise;
promise = new MyPromise((resolve, reject) => {
this.prototype.resolvePromise(promise, value, resolve, reject);
});
return promise;
};
复制代码
test.js
let MyPromise = require('./MyPromise.js');
MyPromise.resolve(1111).then((value) => {
console.log('value1', value);
return new MyPromise((resolve, reject) => {
resolve(2222);
})
}).then((value) => {
console.log('value2', value);
})
复制代码
打印结果:
value1 1111
value2 2222
因为传入的value
有多是普通值,有多是thenable
,也有多是另外一个Promise
,因此调用resolvePromise
进行解析。
Promise.reject
方法Promise.reject
用来生成一个rejected
失败态的Promise
。
MyPromise.js
MyPromise.reject = function(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
};
复制代码
test.js
let MyPromise = require('./MyPromise.js');
MyPromise.reject(1111).then((value) => {
console.log('value1', value);
return new MyPromise((resolve, reject) => {
resolve(2222);
})
}).then((value) => {
console.log('value2', value);
}).catch(reason => {
console.log('reason', reason);
});
复制代码
打印结果:
reason 1111
Promise.deferred
方法Promise.deferred
能够用来延迟执行resolve
和reject
。
MyPromise.js
MyPromise.deferred = function() {
let dfd = {};
dfd.promies = new MyPromise((resolve, reject) => {
dfd.resolve = resolve;
dfd.rfeject = reject;
});
return dfd;
};
复制代码
这样,你就能够在外部经过调用dfd.resolve()
和dfd.reject()
来决议该Promise
。
Promise
链假设这样一个场景,咱们有一个很长的Promise
链式调用,这些Promise
是依次依赖的关系,若是链条中的某个Promise
出错了,就不须要再向下执行了,默认状况下,咱们是没法实现这个需求的,由于Promise
不管是then
仍是catch
都会返回一个Promise
,都会继续向下执行then
或catch
。举例:
new Promise(function(resolve, reject) {
resolve(1111)
}).then(function(value) {
// "ERROR!!!"
}).catch()
.then()
.then()
.catch()
.then()
复制代码
有没有办法让这个链式调用在ERROR!!!的后面就停掉,彻底不去执行链式调用后面全部回调函数呢?
咱们本身封装一个Promise.stop
方法。
MyPromise.js
MyPromise.stop = function() {
return new Promise(function() {});
};
复制代码
stop
中返回一个永远不执行resolve
或者reject
的Promise
,那么这个Promise
永远处于pending
状态,因此永远也不会向下执行then
或catch
了。这样咱们就中止了一个Promise
链。
new MyPromise(function(resolve, reject) {
resolve(1111)
}).then(function(value) {
// "ERROR!!!"
MyPromise.stop();
}).catch()
.then()
.then()
.catch()
.then()
复制代码
可是这样会有一个缺点,就是链式调用后面的全部回调函数都没法被垃圾回收器回收。
Promise
链上返回的最后一个Promise
出现错误看以下例子:
new Promise(function(resolve) {
resolve(42)
}).then(function(value) {
a.b = 2;
});
复制代码
这里a不存在,因此给a.b赋值是一个语法错误,onFulfilled
回调函数是包在try...catch
中执行的,错误会被catch
到,可是因为后面没有then
或catch
了,这个错误没法被处理,就会被Promise
吃掉,没有任何异常,这就是常说的Promise有可能会吃掉错误。
那么咱们怎么处理这种状况呢?
方法一
就是咱们前面已经实现过的done()
。
new Promise(function(resolve) {
resolve(42)
}).then(function(value) {
a.b = 2;
}).done();
复制代码
done()
方法至关于一个catch
,可是却再也不返回Promise
了,注意done()
方法中不能出现语法错误,不然又没法捕获了。
方法二
普通错误监听window
的error
事件能够实现捕获
window.addEventListener('error', error => {
console.log(error); // 不会触发
});
复制代码
Promise没有被onRejected()
处理的错误须要监听unhandledrejection
事件
window.addEventListener('unhandledrejection', error => {
console.log('unhandledrejection', error); // 能够触发,并且还能够直接拿到 promise 对象
});
复制代码
相关单元测试以及完整代码能够到个人github查看,若是对你有帮助的话,就来个star吧~