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);
};
}
}
});
});
};