楼主下去看了下Promise/A+, 这是Promise实现所要遵循的标准, 看了之后模拟了一份, 目前已经打包好放在promise-polyfill上。弄懂promise不容易啊。发出来大家学习啦~
export default class Promise {
// internal method
resolvePromise(y) {
if (this.status === 'pending') {
this.status = 'fulfilled'
this.value = y
if (Array.isArray(this.nextPromises)) {
this.nextPromises.forEach((nextPromise, index) => {
const onFulfilled = this.onFulfilleds[index]
if (typeof onFulfilled === 'function') {
const y = onFulfilled(y)
Promise.Resolve(nextPromise, this.value)
this.onFulfilleds[index] = null
}
})
}
}
}
// internal method
rejectPromise(r) {
if (this.status === 'pending') {
this.status = 'rejected'
this.result = r
if (Array.isArray(this.nextPromises)) {
this.nextPromises.forEach((nextPromise, index) => {
const onRejected = this.onRejecteds[index]
if (typeof onRejected === 'function') {
const x = onRejected(r)
Promise.Resolve(nextPromise, this.result)
this.onRejecteds[index] = null
}
})
}
}
}
// internal method
static Resolve(nextPromise, x) {
if (nextPromise === x) { throw new TypeError() }
if (x instanceof Promise) {
x.then(nextPromise.resolvePromise, nextPromise.rejectPromise)
}
if (typeof x === 'object' || typeof x === 'function') {
const then = x.then
if (typeof then === 'function') {
const resolvePromise = nextPromise.resolvePromise.bind(nextPromise)
const rejectPromise = nextPromise.rejectPromise.bind(nextPromise)
try {
then.call(x, resolvePromise, rejectPromise)
} catch (e) {
nextPromise.rejectPromise(e)
}
} else {
nextPromise.resolvePromise(x)
}
} else {
nextPromise.resolvePromise(x)
}
}
constructor(executor) {
this.status = 'pending'
const resolvePromise = this.resolvePromise.bind(this)
const rejectPromise = this.rejectPromise.bind(this)
executor(resolvePromise, rejectPromise)
}
then(onFulfilled, onRejected) {
const nextPromise = new Promise((resolve, reject) => {
setTimeout(() => {
if (this.status === 'fulfilled') {
const x = onFulfilled(this.value)
Promise.Resolve(nextPromise, x)
} else if (this.status === 'rejected') {
const x = onRejected(this.result)
Promise.Resolve(nextPromise, x)
} else {
this.onFulfilleds = this.onFulfilleds || []
this.onRejecteds = this.onRejecteds || []
this.nextPromises = this.nextPromises || []
const length = this.nextPromises.length
(typeof onFulfilled === 'function') && (this.onFulfilleds[length] = onFulfilled)
(typeof onRejected === 'function') && (this.onRejecteds[length] = onRejected)
this.nextPromises.push(nextPromise)
}
}, 0)
})
return nextPromise
}
}
--------------------------之前的东东
Promise.resolve(1).then(arg => {
return new Promise(arg)
}).then(arg => console.log(arg))
这串代码没有任何输出结果,问了下gitter,说原因是new Promise(arg)是一个状态为Pending的promise对象, 会在这条链上卡主, 不会往下执行. 这让我感到有点困惑, 赶紧去翻了下MDN.MDN是这样描述then方法的.
the then method returns a Promise, you can easily chain then calls. Values returned from the onFulfilled or onRejected callback functions will be automatically wrapped in a resolved promise.
看了MDN的描述,百思不得其解. 对Promise的内部原理甚为困惑. 一个promise对象(状态是fulfilled)调用then的时候会生成一个promise对象, 这个promise对象是pending的, 会异步执行then方法的第一个回调方法, 然后Promise内部是如何包装then方法的返回值的呢?
楼主有一个假设, 用代码描述出来, 不知道是否正确....
function then(resolveHandler, rejectHandler) {
const newPromise = new Promise((resolve, reject) => {
setTimeout(() => {
// 如果调用then方法的promise的status是rejected
if(this.status === 'rejected') {
rejectHandler(this.result)
return
}
// 不是rejected 就是fulfilled
const returnValue = resolveHandler()
// 如果returnValue不是promise类型的话
if (returnValue.___proto__ !== Promise) {
wrapPromise = Promise.resolve(returnValue) //包装返回值
wrapPromise.then(resolve)
} else {
returnValue.then(resolve, reject)
}
}, 0)
})
return newPromise
}
楼主想了之后觉得then是这样的. 大神们给出新姿势~
最适合学习Promise+规范的Promise实现:
https://github.com/abdulapopo...
非常短、很清晰、很容易理解,强烈建议结合规范通读。
———————— 后更
再次一句话来说明:Promise.prototype.then
回调里面的返回值,是通过一个变量/私有API保存的,不是return出来的,想接收/包装返回值得在Promise状态完成了之后通知执行回调函数。
我再简单的举例,一个简单的异步任务如何拿到值:
var foo = (callback) => {
//通过回调函数拿值
setTimeout(function () {
callback(1);
});
};
promise进行一下扁平化的封装
var Promise = function (callback) {
if (!(this instanceof Promise)) {
return new Promise(callback);
}
var $this = this;
setTimeout(function () {
callback(function (value) {
//执行callback
$this.callback(value);
});
});
}
Promise.prototype.then = function (resolveHandler) {
this.callback = resolveHandler;
return this;
};
Promise(function (resolve) {
setTimeout(function () {
resolve(1);
}, 300)
}).then(function (value) {
console.log(value);
});
//300ms后输出1
正常返回int,string类型都是比较好处理,而返回一个Promise该如何处理呢?—— 使用回调链啊
然后我把原回答的代码再次简化了一下,当然这个代码只能大概展现then对于返回值处理的原理,真正要完成Promise还有很多的细节处理。
—————— 下面是原回答:
看了半天有点没太懂,在chrome dev跑了下代码发现你的代码报错了,导致了new Promise
那里卡住了。
Promise.resolve(1).then(arg => {
return new Promise(arg);//这里直接是new Promise(1),API不支持
}).then(arg => console.log(arg))
然后回答你后面的困惑,then
的Promise返回值应该进行异步包装,并且仅依靠promise的公开API是无法实现then返回的包装的,需要一层链进行包装才可以。
简单的说就是:Promise.prototype.then
中,正常的返回值,仅需要进行Promise一层包装即可,而Promise类型的返回值,则需要操作私有API进行回调链的包装,大概类似下面这样:
//为了例子简单点,只做一个resolveHandler
Promise.prototype.then = function(resolveHandler) {
var promise = this;
return new Promise((resolve, reject) => {
var newPromise = this;
setTimeout(function () {
if (promise.status == 'pending') {//如果当前Promise的任务没有完成
//如果已经有了回调函数onFulfilled,则再包装出回调链 => 这个回调函数要在Promise状态完成后执行
if (promise.onFulfilled) {
//这里是重点,这里是重点,这里是重点,重要的事情说三遍
const oldOnFulfilled = promise.onFulfilled;
promise.onFulfilled = () => {
//进行链传递
var oldValue = oldOnFulfilled();
//如果上一个promise也返回了一个promise,则把当前的函数压入上一个promise链中
if (oldValue.___proto__ === Promise)
newPromise.onFulfilled = resolveHandler;
else
resolveHandler(oldValue);
};
} else {
//没有回调函数,则压入回调函数
promise.onFulfilled = () => {
//传递返回值
resolveHandler(promise.result);
};
}
}
});
});
};
研究过很长一段时间的Promise,所以自己也实现过一个Promise-polyfill,可以参考下实现的细节。
个人网站:听说
https://zhuanlan.zhihu.com/p/...
代码写的有问题。new Promise
接受两个参数resolve, reject
,then
接受两个参数resolved, rejected
(都是函数)resolved
获得的是resolve
传给它的值;同样,rejected
获得的是也是reject
的值。
何不参考Promise中then方法的返回值问题
楼主下去看了下Promise/A+, 这是Promise实现所要遵循的标准, 看了之后模拟了一份, 目前已经打包好放在promise-polyfill上。弄懂promise不容易啊。发出来大家学习啦~
export default class Promise {
// internal method
resolvePromise(y) {
if (this.status === 'pending') {
this.status = 'fulfilled'
this.value = y
if (Array.isArray(this.nextPromises)) {
this.nextPromises.forEach((nextPromise, index) => {
const onFulfilled = this.onFulfilleds[index]
if (typeof onFulfilled === 'function') {
const y = onFulfilled(y)
Promise.Resolve(nextPromise, this.value)
this.onFulfilleds[index] = null
}
})
}
}
}
// internal method
rejectPromise(r) {
if (this.status === 'pending') {
this.status = 'rejected'
this.result = r
if (Array.isArray(this.nextPromises)) {
this.nextPromises.forEach((nextPromise, index) => {
const onRejected = this.onRejecteds[index]
if (typeof onRejected === 'function') {
const x = onRejected(r)
Promise.Resolve(nextPromise, this.result)
this.onRejecteds[index] = null
}
})
}
}
}
// internal method
static Resolve(nextPromise, x) {
if (nextPromise === x) { throw new TypeError() }
if (x instanceof Promise) {
x.then(nextPromise.resolvePromise, nextPromise.rejectPromise)
}
if (typeof x === 'object' || typeof x === 'function') {
const then = x.then
if (typeof then === 'function') {
const resolvePromise = nextPromise.resolvePromise.bind(nextPromise)
const rejectPromise = nextPromise.rejectPromise.bind(nextPromise)
try {
then.call(x, resolvePromise, rejectPromise)
} catch (e) {
nextPromise.rejectPromise(e)
}
} else {
nextPromise.resolvePromise(x)
}
} else {
nextPromise.resolvePromise(x)
}
}
constructor(executor) {
this.status = 'pending'
const resolvePromise = this.resolvePromise.bind(this)
const rejectPromise = this.rejectPromise.bind(this)
executor(resolvePromise, rejectPromise)
}
then(onFulfilled, onRejected) {
const nextPromise = new Promise((resolve, reject) => {
setTimeout(() => {
if (this.status === 'fulfilled') {
const x = onFulfilled(this.value)
Promise.Resolve(nextPromise, x)
} else if (this.status === 'rejected') {
const x = onRejected(this.result)
Promise.Resolve(nextPromise, x)
} else {
this.onFulfilleds = this.onFulfilleds || []
this.onRejecteds = this.onRejecteds || []
this.nextPromises = this.nextPromises || []
const length = this.nextPromises.length
(typeof onFulfilled === 'function') && (this.onFulfilleds[length] = onFulfilled)
(typeof onRejected === 'function') && (this.onRejecteds[length] = onRejected)
this.nextPromises.push(nextPromise)
}
}, 0)
})
return nextPromise
}
}