Open MyPrototypeWhat opened 2 years ago
callReaction
中...
if (result === reaction.promise) {
reject(new TypeError('Promise-chain cycle'));
} else if (then = isThenable(result)) {
call(then, result, resolve, reject); // 相当于 result.then(resolve,reject)
} else resolve(result);
...
例子:
.then(()=>new Promise((resolve)=>resolve())).then(()=>{console.log(123)})
123
会在前一个Promise resolve
之后输出
try {
new Promise((_,reject)=>{
reject(1)
})
} catch (error) {
console.log('error',error)
}
reject
错误并不能被捕获,因为reject中throw err
部分在微任务中,也就是说trycatch
执行完了,reject
的错误才会抛出,所以无法捕获。
同理在:
new Promise((_,reject)=>{
console.log(a) // a is not defined
})
这个错误也是无法被catch
到的,new Promise(executor)
,在执行executor
时 外层有一个trycatch
,catch
到错误用reject
抛错
很简单,reject
抛错变为同步,让catch
在reject
后
try {
await new Promise((_,reject)=>{
reject(1)
})
} catch (error) {
console.log('error',error) // error 1
}
这就是涉及到了async await
语法糖
将上面代码包装一下:
function* fn(){
try {
yield new Promise((_,reject)=>{
reject(1)
})
} catch (error) {
console.log('error',error) // error 1
}
}
const gen=fn()
const info=gen.next() // { value:Promise, done:false }
if(info.done){
resolve(info.value)
}else{
// reject(1) 所以肯定会走到_throw逻辑中,_throw其实就是调用了gen.throw,将错误抛出
Promise.resolve(info.value).then(_next,_throw)
}
可能会有疑惑,.then(_next,_throw)
不就是个异步了吗?
因为generator
函数,yield
会阻塞下面的执行,所以会等待直到.then
的回调触发
例如
Promise.resolve(10)
.then(2)
.then(Promise.resolve(3))
.then((res) => console.log(res)); // res输出什么呢?
答案是10
,为什么呢?
如果只是应对面试话可以直接这么记:因为上面几个then
内没有返回值
core-js_then的源码
Promise.prototype.then = function () {
// 通过this获取state
var state = getInternalPromiseState(this);
// 创建一个对象,包含promise,reject,resolve
var reaction = newPromiseCapability(
speciesConstructor(this, PromiseConstructor)
);
state.parent = true;
// 如果onFulfilled不是函数,一律是true
reaction.ok = isCallable(onFulfilled) ? onFulfilled : true;
reaction.fail = isCallable(onRejected) && onRejected;
reaction.domain = IS_NODE ? process.domain : undefined;
// 添加到reaction队列中,当状态更改后,遍历reaction,执行callReaction
if (state.state === PENDING) state.reactions.add(reaction);
// 如果状态不为PENDING,则添加到微任务队列中
else
microtask(function () {
callReaction(reaction, state);
});
// 注意这个!!返回的是这个then创建的promise
return reaction.promise;
};
从上面的源码可看出,当then
中传了2
,reaction.ok = true
再转到callReaction
中
// ...
// 前一个promise resolve的值
var value = state.value;
var ok = state.state === FULFILLED;
var handler = ok ? reaction.ok : reaction.fail;
var resolve = reaction.resolve;
var reject = reaction.reject;
var result;
// ...
if (handler) {
// ...
// 如果handler是true,则result = value
if (handler === true) result = value;
}
if (result === reaction.promise) {
reject(new TypeError("Promise-chain cycle"));
} else if ((then = isThenable(result))) {
call(then, result, resolve, reject);
// 看这里,这个resolve是then生成的promsie的resolve
} else resolve(result);
// ...
结合来看,无论 then 中传了什么,只要不是函数,就result = value
,所以例子中2
,Promise.resolve(3)
都没用到,所以最后输出10
Promise部分实现
p.then1().then2()
state(state)
,执行resolve
(或延迟执行,视调用情况而定),触发notify()
,将会遍历reactions
,并执行callReaction
then1
创建state1
,并new
出一个拥有promise
功能的对象(p1
),将其放在state.reactions
中,返回p1.promise
then2
创建state2
,并new
出一个拥有promise
功能的对象(p2
),将其放在state1.reactions
,返回p2.promise
notify
挂载的微任务触发,执行callReaction
,执行对应的reactions
,拿到执行结果result
,然后执行resolve
,触发下一个notify
reaction
保存resolve
或reject
之后需要触发的函数(也就是then的两个参数)notify
用来触发reaction
,因为notify
会将reaction
触发时机变为微任务,所以可以顺利的通过then
函数添加reaction
then
函数返回一个promise
时,这个promise
会被执行then
,即使没有主动调用then
resolve
(internalResolve
)函数,只会在第一个new Promise
时显式调用