手把手实现Promise
基本结构
- Promise 构造函数传入一个函数
new Promise((resolve, reject) => resolve(1))
- 函数中有两个参数为
resolve
和reject
的函数 - Promise 返回一个含有
then
方法的实例p.then()
then
方法可以传入两个函数分别是resolved
来获取Promise
成功状态的值,和rejected
来获取Promise
失败的值.
基本结构代码如下:
function Promise(executor) {
const resolve = () => {
}
const reject = () => {
}
// 执行传入的函数参数
executor(resolve, reject);
}
// 增加then方法
Promise.prototype.then = function (onResolved, onRejected) {
}
增加状态和返回值
基本结构搭建好后,我们知道在使用Promise
中不管是resolve
还是reject
最终都只会出现一种状态和对应的返回结果值。例如下面例子:
// resolve值 只会执行resolve
new Promise(resolve, reject => {
resolve('success');
});
// reject值 只会执行reject
new Promise(resolve, reject => {
reject('reject');
});
// reject值 只会执行resolve()
let p = new Promise((resolve, reject) => {
resolve(1);
reject(2);
});
p.then(data => {
console.log(data); //1
}, error => {
console.log(error);
})
接着继续完善Promise
:
- 增加一个变量
status
记录当前实例状态,三种状态pending、fulfilled、rejected
,默认pending
- 增加一个变量储存
resolve
值 - 增加一个变量储存
reject
值
function Promise(executor) {
this.status = 'pending'; //状态默认为等待
this.value = null; // resolve值
this.reason = null; // reject值
const resolve = value => {
this.value = value;
}
const reject = reason => {
this.reason = reason;
}
executor(resolve, reject);
}
Promise.prototype.then = function (onResolved, onRejected) {
onResolved(this.value);
onRejected(this.reason);
}
这里then放在原型上是因为实例可以直接共享一份原型,而不是每次都需要新建,这样减少内存使用
状态唯一性
上面代码在then
实现中会执行resolve
和reject
两个,会有两个返回值,在真实的Promise
中只会出现一种状态,接下来需要做的是状态的处理:
// 增加状态处理的逻辑
function Promise(executor) {
this.status = 'pending'; //状态默认为等待
this.value = null; // resolve值
this.reason = null; // reject值
const resolve = value => {
// 只有进入等待状态 才能进入解决状态
if (this.status === 'pending') {
this.value = value;
this.status = 'fulfilled';
}
}
const reject = reason => {
// 只有进入等待状态,才能进入拒绝状态
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
}
}
executor(resolve, reject);
}
Promise.prototype.then = function (onResolved, onRejected) {
if (this.status === 'fulfilled') {
onResolved(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
}
上面Promise已经是能正常运行起来了,能正常的输出结果,算是一个初级版本了。
但是如果我们的Promise
执行下面例子:
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('res');
}, 3000)
});
p.then(res => console.log(res)); // 没有输出
并没有输出结果,因为我们的Promise
代码是同步的,而例子中使用异步setTimeout
,而then
方法的实现不会等待异步的fulfilled
状态,而是在pending
状态的时候直接返回了空。
增加异步的支持
解决上面例子的中异步问题,我们需要在then
中保存resolve
和reject
的回调函数,然后在状态变化时候来调用,调整如下:
function Promise(executor) {
this.status = 'pending'; //状态默认为等待
this.value = null; // resolve值
this.reason = null; // reject值
this.onResolvedFunc = Function.prototype; // 使用Function原型作为默认函数值
this.onRejectedFunc = Function.prototype;
const resolve = value => {
// 只有进入等待状态 才能进入解决状态 并触发回调
if (this.status === 'pending') {
this.value = value;
this.status = 'fulfilled';
this.onResolvedFunc(this.value);
}
}
const reject = reason => {
// 只有进入等待状态,才能进入拒绝状态 并触发回调
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
this.onRejectedFunc(this.reason);
}
}
executor(resolve, reject);
}
Promise.prototype.then = function (onResolved, onRejected) {
if (this.status === 'fulfilled') {
onResolved(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
// 储存resolve, reject回调函数
if (this.status === 'pending') {
this.onResolvedFunc = onResolved;
this.onRejectedFunc = onRejected;
}
}
现在我们的Promise
是支持异步了,但是现在又面临新的问题,我们知道Promise
中then
函数中的代码是异步的,请看下面例子:
let p = new Promise((resolve, reject) => {
resolve('2');
});
p.then(res => console.log(res));
console.log('1');
官方Promise
上面例子是先输出1
再输出2
,我们的版本是2
和1
。
我们需要如何实现then
中代码异步化,很简单,放在setTimeout
中执行就可以了,调整后的Promise
代码:
function Promise(executor) {
this.status = 'pending'; //状态默认为等待
this.value = null; // resolve值
this.reason = null; // reject值
this.onResolvedFunc = Function.prototype; // 使用Function原型作为默认函数
this.onRejectedFunc = Function.prototype;
const resolve = value => {
// 只有进入等待状态 才能进入解决状态 并触发回调
setTimeout(() => {
if (this.status === 'pending') {
this.value = value;
this.status = 'fulfilled';
this.onResolvedFunc(this.value);
}
});
}
const reject = reason => {
// 只有进入等待状态,才能进入拒绝状态 并触发回调
setTimeout(() => {
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
this.onRejectedFunc(this.reason);
}
});
}
executor(resolve, reject);
}
Promise.prototype.then = function (onResolved, onRejected) {
if (this.status === 'fulfilled') {
onResolved(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
// 储存resolve, reject回调函数
if (this.status === 'pending') {
this.onResolvedFunc = onResolved;
this.onRejectedFunc = onRejected;
}
}
处理多个then的问题
在正常的Promise
中会出现连续调用多个then,例如:
let p = new Promise((resolve, reject) => {
resolve(1);
});
p.then(res => console.log("res1:", res)); //res1: 1
p.then(res => console.log("res2:", res)); //res2: 1
而我们的Promise
只会输出后面的结果,原因是第二次的then
覆盖了之前的then
,所以最终只会执行一个,我们需要改成数组的形式存放reject和resolve
即可,调整如下:
function Promise(executor) {
this.status = 'pending'; //状态默认为等待
this.value = null; // resolve值
this.reason = null; // reject值
this.onResolvedArray = []; //数组存放
this.onRejectedArray = [];
const resolve = value => {
// 只有进入等待状态 才能进入解决状态 并触发回调
setTimeout(() => {
if (this.status === 'pending') {
this.value = value;
this.status = 'fulfilled';
// 调用所有的then resolve
this.onResolvedArray.forEach(fun => fun(this.value));
}
});
}
const reject = reason => {
// 只有进入等待状态,才能进入拒绝状态 并触发回调
setTimeout(() => {
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
// 调用所有的then reject
this.onRejectedArray.forEach(fun => fun(this.reason));
}
});
}
executor(resolve, reject);
}
Promise.prototype.then = function (onResolved, onRejected) {
if (this.status === 'fulfilled') {
onResolved(this.value);
}
if (this.status === 'rejected') {
onRejected(this.reason);
}
// 储存resolve, reject回调函数
if (this.status === 'pending') {
// 保存resolve reject
this.onResolvedArray.push(onResolved);
this.onRejectedArray.push(onRejected);
}
}
现在我们的Promise
可以执行多个then
了。
增加链式调用支持
看一个例子:
const p = new Promise((resolve, reject) => {
resolve(1);
});
//1.支持 then后面接着调用then
p.then(res => {
console.log(res);
})
.then(res => {
console.log(222);
});
// 依次输出 1 2
思路:
- 要实现
then
的链式调用必须在then
函数中返回一个Promise
才能继续支持调用then
- 也就是说
then
中的resolve
和reject
函数中中必须返回Promise
- 我们将
status
三种状态的执行结果保存通过一个新的Promise
返回
调整后:
Promise.prototype.then = function (onResolved, onRejected) {
if (this.status === 'fulfilled') {
// 返回一个新的Promise实例
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
// 保存resolve执行的结果
let result = onResolved(this.value);
resolve(result);
} catch (e) {
reject(e);
}
});
});
}
if (this.status === 'rejected') {
return new Promise((resolve, reject) => {
setTimeout(() => {
try {
let result = onRejected(this.reason);
resolve(result);
} catch (e) {
reject(e);
}
})
})
}
// 储存resolve, reject回调函数
if (this.status === 'pending') {
// 保存resolve reject
return new Promise((resolve, reject) => {
this.onResolvedArray.push(() => {
try {
let result = onResolved(this.value);
resolve(result);
} catch (e) {
reject(e)
}
});
this.onRejectedArray.push(() => {
try {
let result = onRejected(this.reason);
resolve(result);
} catch (e) {
reject(e)
}
});
});
}
}
三种状态下的
resolve、reject
函数都需要通过新的Promise
包装一层在返回结果 这样确实可以支持then
链式调用了,但是有一种情况,如下例子:
let p4 = new Promise((resolve, reject) => {
resolve(1)
});
p4.then(res => {
console.log(res);
return new Promise((resolve, reject) => {
resolve(2);
});
})
.then(res => {
console.log(res)
})
.then(res => {
console.log(4)
})
我们在第一次then
函数中返回一个 新的 Promise
,接着继续执行了两次then
,实际输出是有问题的,没有按预期的输出结果1 2 4
,少输出了2
我们目前的Promise中then只是处理了普通resolve reject返回值,如果遇到了Promise也被当作正常值处理就拿不到值,所以我们需要对Promise做处理。
新增一个函数resolvePromise
处理Promise
和 普通值,如下:
// 新增一个函数处理Promise 和 普通值
const resolvePromise = (promise, result, resolve, reject) => {
// 当promise 和 result相等
if (promise === result) {
reject(new TypeError('error due to circular reference'));
}
let consumed = false,// 是否已经执行
thenable = null; // 保存then函数
// 如果result是Promise 实例
if (result instanceof Promise) {
if (result.status === 'pending') {
result.then(function (data) {
// 继续递归调用
resolvePromise(promise, data, resolve, reject);
}, reject)
} else {
result.then(resolve, reject);
}
return;
}
const isComplexResult = target => (typeof target === 'function' || typeof target === 'object') && (target !== null);
// 如果result 疑似 Promise
if (isComplexResult(result)) {
try {
thenable = result.then;
// 如果result有then方法
if (typeof thenable === 'function') {
thenable.call(result, function (data) {
if (consumed) {
return;
}
consumed = true;
// 递归
return resolvePromise(promise, data, resolve, reject);
}, function(error) {
if (consumed) return;
consumed = true;
return reject(error);
})
}
} catch (e) {
if (consumed) return;
consumed = true;
return reject(e);
}
} else {
resolve(result);
}
}
promise: 需要返回的Promise
result: reject 或 resolve 执行的结果
resolve: 需要返回的Promise 的 resolve
reject: 需要返回的Promise 的 reject
所谓疑似就是result是function或者对象并且有then方法,我们也当做Promise来处理
上面代码实现 多次使用递归和 pending状态处理,需要反复理解才能想通 [dog]
接着在then
中result
返回值使用resolvePromise
处理:
Promise.prototype.then = function (onResolved, onRejected) {
// 保存promise
let promise = null;
if (this.status === 'fulfilled') {
// 返回一个新的Promise实例
return promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// 保存resolve执行的结果
let result = onResolved(this.value);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
if (this.status === 'rejected') {
return promise = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let result = onRejected(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
// 储存resolve, reject回调函数
if (this.status === 'pending') {
// 保存resolve reject
return promise = new Promise((resolve, reject) => {
this.onResolvedArray.push(() => {
try {
let result = onResolved(this.value);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e)
}
});
this.onRejectedArray.push(() => {
try {
let result = onRejected(this.reason);
resolvePromise(promise, result, resolve, reject);
} catch (e) {
reject(e)
}
});
});
}
}
完整代码:
function Promise(executor) {
this.status = 'pending'; //状态默认为等待
this.value = null; // resolve值
this.reason = null; // reject值
this.onResolvedArray = []; //数组存放
this.onRejectedArray = [];
const resolve = value => {
if (value instanceof Promise) {
return value.then(resolve, reject);
}
// 只有进入等待状态 才能进入解决状态 并触发回调
setTimeout(() => {
if (this.status === 'pending') {
this.value = value;
this.status = 'fulfilled';
// 调用所有的then resolve
this.onResolvedArray.forEach(fun => fun(value));
}
});
}
const reject = reason => {
// 只有进入等待状态,才能进入拒绝状态 并触发回调
setTimeout(() => {
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
// 调用所有的then reject
this.onRejectedArray.forEach(fun => fun(reason));
}
});
}
executor(resolve, reject);
}
const resolvePromise = (promise2, result, resolve, reject) => {
// 当promise 和 result相等 直接返回错误
if (result === promise2) {
reject(new TypeError('error due to circular reference'));
}
let consumed = false; //是否执行了
let thenable; // 保存then函数
// 如果result是Promise 实例
if (result instanceof Promise) {
if (result.status === 'pending') {
result.then(function (data) {
// 继续递归调用
resolvePromise(promise2, data, resolve, reject);
}, reject);
} else {
result.then(resolve, reject);
}
return;
}
let isComplexResult = target => (typeof target === 'function' || typeof target === 'object') && (target !== null);
// 如果result 疑似 Promise
if (isComplexResult(result)) {
try {
thenable = result.then;
// 如果result有then方法
if (typeof thenable === 'function') {
thenable.call(result, function (data) {
if (consumed) {
return;
}
consumed = true;
// 递归
return resolvePromise(promise2, data, resolve, reject);
}, function(error) {
if (consumed) return;
consumed = true;
return reject(error);
})
} else {
resolve(result);
}
} catch (e) {
if (consumed) return;
consumed = true;
return reject(e);
}
} else {
resolve(result);
}
}
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error };
// 保存promise
let promise2 = null;
if (this.status === 'fulfilled') {
// 返回一个新的Promise实例
return promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// 保存resolve执行的结果
let result = onResolved(this.value);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
if (this.status === 'rejected') {
return promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let result = onRejected(this.reason);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
// 储存resolve, reject回调函数
if (this.status === 'pending') {
// 保存resolve reject
return promise2 = new Promise((resolve, reject) => {
this.onResolvedArray.push(() => {
try {
let result = onResolved(this.value);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e)
}
});
this.onRejectedArray.push(() => {
try {
let result = onRejected(this.reason);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e)
}
});
});
}
}
上面代码增加一些参数容错处理onResolved、onRejected
设置默认参数,resolve
函数,value
如果是Promise直接调用
onResolved = typeof onResolved === 'function' ? onResolved : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error };
const resolve = value => {
if (value instanceof Promise) {
return value.then(resolve, reject);
}
}
Promise 穿透现象
什么是穿透现象,看下面例子:
let p = new Promise((resolve, reject) => {
resolve(1);
});
p.then(null)
.then(() => {
console.log(2)
});
// 2
简而言之如果第一个then函数是null,会跳过当前then继续往下执行 我们实现的Promise中已经支持穿透现象,当参数为
null
给onResolved、onRejected
设置默认函数即可。
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error };
//...
}
静态方法的支持
- Promise.prototype.catch
- Promise.resolve
- Promise.reject
- Promise.all
- Promise.race
Promise.prototype.catch
// demo
let promise1 = new Promise((res, rej) => {
rej('error');
});
promise1.then(data => {
console.log(data)
}).catch(error => {
console.log(error); // error
});
// 实现
Promise.prototype.catch = function (catchFunc) {
return this.then(null, catchFunc);
}
使用then的第二个参数来捕获来实现
Promise.resolve 和 Promise.reject
使用场景:
Promise.resolve('res').then(data => {
console.log(data);
})
console.log(1);
Promise.resolve
返回新的Promise
实例和实例的resolve
函数执行后的结果,reject
同理,实现代码:
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
resolve(value);
});
}
Promise.reject = function (value) {
return new Promise((resolve, reject) => {
reject(value);
});
}
Promise.all
Promise.all
返回一个Promise
,接受一个Promise
数组, 当所有Promise
都resolve
则返回resolve
,有一个失败返回reject
.
看下例子:
let p1 = new Promise((resolve, reject) => {
resolve(1);
});
let p2 = new Promise((resolve, reject) => {
resolve(2);
});
Promise.all([p1, p2]).then(res => {
console.log(res);
});
执行结果输出:[1, 2]
.
实现思路:
- 遍历执行所有的
Promise
- 保存每一个
Promise
的resolve
执行结果 - 执行完成后返回执行结果
- 如果遍历的时候有一个出现
reject
则直接返回reject
实现代码:
Promise.all = function (promiseArray) {
// 非数组报错
if (!Array.isArray(promiseArray)) {
throw new TypeError('arguments should be an array');
}
return new Promise((resolve, reject) => {
try {
let resultArray = [];
const length = promiseArray.length;
for (let i=0; i<length; i++) {
// 执行Promise.then
promiseArray[i].then(data => {
// 保存结果
resultArray.push(data);
// 完成所有promise resolve结果
if (resultArray.length === length) {
resolve(resultArray);
}
// 其中有一个出现reject 则返回reject
}, reject);
}
} catch(e) {
// 出现异常直接reject
reject(e);
}
});
}
Promise.race
和all
不一样,all
是所有Promise
都resolve才resolve,而race是当有一个Promise为先完成resolve就resolve.这里是竞争关系,实现思路是直接执行所有的Promise即可,谁先完成就会先返回
实现代码:
Promise.race = function(promiseArray) {
if (!Array.isArray(promiseArray)) {
throw new TypeError('arguments should be an array');
}
return new Promise((resolve, reject) => {
try {
for (let i=0; i<promiseArray.length; i++) {
promiseArray[i].then(resolve, reject);
}
} catch (e) {
reject(e);
}
});
}
一些细节问题
完成Promise
静态方法之后Promise
所有的功能就已经完成了,还需要处理一些细节问题:
executor 使用try catch包裹
function Promise(executor) {
// executor 使用try catch包裹
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
完整代码
function Promise(executor) {
this.status = 'pending'; //状态默认为等待
this.value = null; // resolve值
this.reason = null; // reject值
this.onResolvedArray = []; //数组存放
this.onRejectedArray = [];
const resolve = value => {
if (value instanceof Promise) {
return value.then(resolve, reject);
}
// 只有进入等待状态 才能进入解决状态 并触发回调
setTimeout(() => {
if (this.status === 'pending') {
this.value = value;
this.status = 'fulfilled';
// 调用所有的then resolve
this.onResolvedArray.forEach(fun => fun(value));
}
});
}
const reject = reason => {
// 只有进入等待状态,才能进入拒绝状态 并触发回调
setTimeout(() => {
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
// 调用所有的then reject
this.onRejectedArray.forEach(fun => fun(reason));
}
});
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
const resolvePromise = (promise2, result, resolve, reject) => {
// 当promise 和 result相等 直接返回错误
if (result === promise2) {
reject(new TypeError('error due to circular reference'));
}
let consumed = false; //是否执行了
let thenable; // 保存then函数
// 如果result是Promise 实例
if (result instanceof Promise) {
if (result.status === 'pending') {
result.then(function (data) {
// 继续递归调用
resolvePromise(promise2, data, resolve, reject);
}, reject);
} else {
result.then(resolve, reject);
}
return;
}
let isComplexResult = target => (typeof target === 'function' || typeof target === 'object') && (target !== null);
// 如果result 疑似 Promise
if (isComplexResult(result)) {
try {
thenable = result.then;
// 如果result有then方法
if (typeof thenable === 'function') {
thenable.call(result, function (data) {
if (consumed) {
return;
}
consumed = true;
// 递归
return resolvePromise(promise2, data, resolve, reject);
}, function(error) {
if (consumed) return;
consumed = true;
return reject(error);
})
} else {
resolve(result);
}
} catch (e) {
if (consumed) return;
consumed = true;
return reject(e);
}
} else {
resolve(result);
}
}
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : error => { throw error };
// 保存promise
let promise2 = null;
if (this.status === 'fulfilled') {
// 返回一个新的Promise实例
return promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// 保存resolve执行的结果
let result = onResolved(this.value);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
if (this.status === 'rejected') {
return promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let result = onRejected(this.reason);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
// 储存resolve, reject回调函数
if (this.status === 'pending') {
// 保存resolve reject
return promise2 = new Promise((resolve, reject) => {
this.onResolvedArray.push(() => {
try {
let result = onResolved(this.value);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e)
}
});
this.onRejectedArray.push(() => {
try {
let result = onRejected(this.reason);
resolvePromise(promise2, result, resolve, reject);
} catch (e) {
reject(e)
}
});
});
}
}
// catch
Promise.prototype.catch = function (catchFunc) {
return this.then(null, catchFunc);
}
// resolve
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
resolve(value);
});
}
//reject
Promise.reject = function (value) {
return new Promise((resolve, reject) => {
reject(value);
});
}
//all
Promise.all = function (promiseArray) {
// 非数组报错
if (!Array.isArray(promiseArray)) {
throw new TypeError('arguments should be an array');
}
return new Promise((resolve, reject) => {
try {
let resultArray = [];
const length = promiseArray.length;
for (let i=0; i<length; i++) {
promiseArray[i].then(data => {
resultArray.push(data);
// 完成所有promise resolve结果
if (resultArray.length === length) {
resolve(resultArray);
}
// 其中有一个出现reject 则返回reject
}, reject);
}
} catch(e) {
// 出现异常直接reject
reject(e);
}
});
}
//race
Promise.race = function(promiseArray) {
if (!Array.isArray(promiseArray)) {
throw new TypeError('arguments should be an array');
}
return new Promise((resolve, reject) => {
try {
for (let i=0; i<promiseArray.length; i++) {
promiseArray[i].then(resolve, reject);
}
} catch (e) {
reject(e);
}
});
}
总结
链式调用resolvePromise
实现比较难理解,需要反复阅读体会。
引用
书籍:前端开发核心知识进阶:50 讲从夯实基础到突破瓶颈