Daily-Interview-Question
Daily-Interview-Question copied to clipboard
第 64 题:模拟实现一个 Promise.finally
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
window.Promise && !('finally' in Promise) && !function() {
Promise.prototype.finally = function(cb) {
cb = typeof cb === 'function' ? cb : function() {};
var Fn = this.constructor; // 获取当前实例构造函数的引用
// 接受状态:返回数据
var onFulfilled = function(data) {
return Fn.resolve(cb()).then(function() {
return data
})
};
// 拒绝状态:抛出错误
var onRejected = function(err) {
return Fn.resolve(cb()).then(function() {
throw err
})
};
return this.then(onFulfilled, onRejected);
}
}();
/*********************** 测试 ***********************/
const p = new Promise((resolve, reject) => {
console.info('starting...');
setTimeout(() => {
Math.random() > 0.5 ? resolve('success') : reject('fail');
}, 1000);
});
// 正常顺序测试
p.then((data) => {
console.log(`%c resolve: ${data}`, 'color: green')
})
.catch((err) => {
console.log(`%c catch: ${err}`, 'color: red')
})
.finally(() => {
console.info('finally: completed')
});
// finally 前置测试
p.finally(() => {
console.info('finally: completed')
})
.then((data) => {
console.log(`%c resolve: ${data}`, 'color: green')
})
.catch((err) => {
console.log(`%c catch: ${err}`, 'color: red')
});
window.Promise.prototype = {
finally: function(callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
}
}
抄了个...
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => {
callback();
return value;
},
reason => {
callback();
throw reason
}
);
};
为什么需要Promise.resolve(callback()).then(() => value) 而不能直接执行callback, return value
Promise.prototype.finally = function(callback) {
return this.then(
() => {
callback();
},
() => {
callback();
}
);
};
Promise.prototype.finally = function(callback){
const constructor = this.constructor
return this.then(value => {
return constructor.resolve(callback()).then(() => value)
}),
reason => {
return constructor.resolve(callback()).then(() => throw reason)
}
}
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => { callback(); return value; }, reason => { callback(); throw reason } ); };为什么需要Promise.resolve(callback()).then(() => value) 而不能直接执行callback, return value
因为callback如果是个异步操作,返回promise呢.希望等callback执行完再接着执行
https://github.com/taylorhakes/promise-polyfill/blob/master/src/finally.js
finally是一个关键字,在IE低版本会引发解析错误,若兼容IE不能直接object.key语法.
Promise.prototype['finally'] = function (callback) {
var constructor = this.constructor;
return this.then(
function(value) {
// @ts-ignore
return constructor.resolve(callback()).then(function() {
return value;
});
},
function(reason) {
// @ts-ignore
return constructor.resolve(callback()).then(function() {
// @ts-ignore
return constructor.reject(reason);
});
}
);
}
看了这个问题才知道,原来 promise 的 finally 只是不管成功还是失败都会执行而已,而不会永远最后执行😂
new Promise((resolve, reject) => {
resolve();
}).finally(() => {
console.log('finally1');
}).then(() => {
console.log('then');
}).finally(() => {
console.log('finally2');
});
finally1
then
finally2
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); };
想问下,这里先通过P缓存this.constructor,后面再通过P.resolve的方式调用是有什么目的么,为什么不是直接value => Promise.resolve(callback()).then(() => value),和reason => Promise.resolve(callback()).then(() => { throw reason })~ 谢谢
来个简洁版的:
finally(callback) {
return this.then(
(res) => {
callback();
return res;
},
(err) => {
callback();
return err;
}
);
}
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); };
看一个多月,还是没看懂,哪位大神能逐句解释一下
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); };想问下,这里先通过P缓存this.constructor,后面再通过P.resolve的方式调用是有什么目的么,为什么不是直接
value => Promise.resolve(callback()).then(() => value),和reason => Promise.resolve(callback()).then(() => { throw reason })~ 谢谢
同问
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); };想问下,这里先通过P缓存this.constructor,后面再通过P.resolve的方式调用是有什么目的么,为什么不是直接
value => Promise.resolve(callback()).then(() => value),和reason => Promise.resolve(callback()).then(() => { throw reason })~ 谢谢
我觉得是为了兼容那些自定义的Promise版本。比如说可以自己实现一个Promise叫MyPromise,像resolve和reject这些静态方法都是挂载在MyPromise上的。通过这样let P = this.constructor;写,兼容性更好吧。
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value, () => value),
reason => P.resolve(callback()).then(() => { throw reason }, () => {throw reason})
);
};
如上在阮大神关于 finally 的写法中补充了一点。不知是否正确,欢迎探讨和学习。
callback 可能存在返回 promise,而该 promise 如果 reject,P.resolve 就会 reject,如果 P.resolve().then() 没有设置第二个回调,那么 this.then 的最终状态将是 reject 的状态,这与 es6 中所表现出来的 finally 的行为不一致。
如下是 es6 所表现的行为:
new Promise((resolve, reject) => resolve(111)).finally(Promise.reject(222)) // 此时 es6 表现的行为状态为 resolve(111),而非 reject(222)
@webfool 新加的代码与规范中规定的行为不符合, 你的代码:
new Promise((resolve, reject) => resolve(111))
.finally(Promise.reject(222)) // Promise {<resolved>: 111}
之所以最终返回的 Promise的状态为 resolve(111), 那是因为你传给finally函数的参数的不是函数类型, 而是一个Promise对象.
如果对代码进行小小修改, 就发现 @lvtraveler 实现的 finally方法与 es6 的 Promise的 finally 的行为一致:
new Promise((resolve, reject) => resolve(111))
.finally(() => Promise.reject(222)) // Promise {<rejected>: 222}
现在再解释为什么你的代码得到Promise {<resolved>: 111}的结果, 即代码是如何执行的.
在规范中对这种传给finally函数的参数的不是函数类型情况的处理如下:
Promise.prototype.finally = function(onFinally) {
if (typeof onFinally !== 'function') {
return this.then(onFinally, onFinally)
}
// ...
}
那么this.then(onFinally, onFinally)又是怎么处理的呢?
对于在 then方法中传入非函数类型的参数的情况, Promise/A+规范 2.2.1.1 和 2.2.1.2规定如下:
A promise’s
thenmethod accepts two arguments:promise.then(onFulfilled, onRejected)
- 2.2.1 Both
onFulfilledandonRejectedare optional arguments:
- 2.2.1.1 If
onFulfilledis not a function, it must be ignored.- 2.2.1.2 If
onRejectedis not a function, it must be ignored.
注: 这里没有给出 ES6 规范中对于 Promise 的规定, 是因为ES6 的 Promise 行为遵循 Promise/A+ 规范, 另外我也没看过 ES6 的规范
所以代码最后相当于:
Promise.prototype.finally = function(onFinally) {
if (typeof onFinally !== 'function') {
return this.then() // 注: bluebird 也是这么实现的: https://github.com/petkaantonov/bluebird/blob/master/src/finally.js#L93
}
// ...
}
对于 onFulfilled and onRejected 为非函数类型的情况, 具体的执行行为规范2.2.7.3 和 2.2.7.4 规定如下:
promise2 = promise1.then(onFulfilled, onRejected);
- If
onFulfilledis not a function andpromise1is fulfilled,promise2must be fulfilled with the same value aspromise1.- If
onRejectedis not a function andpromise1is rejected,promise2must be rejected with the same reason aspromise1.
根据对规范的理解, 具体的执行行为用代码表示为:
Promise.prototype.finally = function(onFinally) {
if (typeof onFinally !== 'function') {
return this.then(
val => val,
reason => {
throw reason
}
)
}
// ...
}
再回到最初你的代码, 就知道最终finally返回的 Promise的状态由new Promise.resolve(111) 这个Promise来决定
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); };看一个多月,还是没看懂,哪位大神能逐句解释一下
第一步获取构建函数,这里constructor就是获取,为什么用这个呢?主要是以前的promise实现有第三方的存在 后面返回一个then对象,then接受两个方法,这里统一用resolve接收,之后等待callback执行完成后继续返回结果和抛出异常
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); };看一个多月,还是没看懂,哪位大神能逐句解释一下
首先是生成函数,这里构造函数就是获取,为什么用这个呢呢?主要是以前的promise实现有第三方的存在 后面返回一个对象,然后接受两个方法,这里统一用resolve接收,之后等待回调执行完成后继续返回结果和抛出异常
有一点不明白,为什么异常处理要写在then的第二个参数里,而不是用catch方法
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => { callback(); return value; }, reason => { callback(); throw reason } ); };为什么需要Promise.resolve(callback()).then(() => value)
而不能直接执行callback, return value
这里都不需要有 let P = this.constructor; 这一句了吧
Promise._finally = function(cb) {
return this.then(value => { cb(); return value }, err => { cb(); throw err})
}
Promise.prototype.myFinally = function (func) { return this.then(func) } 直接这样就好了呀
PromiseA.prototype.finally = (fn) => {
// 保证了fn执行在前.. 但是有点绕
return this.then((param)=>{
// 万一 fn reject了
return PromiseA.resolve(fn()).then(()=>param, ()=>param);
}, (err) =>{
// 万一 fn reject了
return PromiseA.resolve(fn()).then(()=>{
throw err;
}, ()=>{
throw err;
});
})
}
- finally 方法 , 不管 Promise 对象最后状态如何,都会执行的操作, 返回的依然是个Promise;
- 参数 cb 没有接收之前 Promise 的值, 只是执行 cb 并继承之前的状态
finally (cb) {
return this.then(
value => Promise.resolve(cb()).then(() => value),
reason => Promise.resolve(cb()).then(() => { throw reason })
);
}
window.Promise.prototype = { finally: function(callback) { let P = this.constructor; return this.then( value => P.resolve(callback()).then(() => value), reason => P.resolve(callback()).then(() => { throw reason }) ); } }抄了个...
你这样是不是把prototype都覆盖了
Promise.prototype.myFinally = async function (cb) {
const pr = this;
try {
await pr;
} finally {
cb && cb();
}
};
const start = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const temp = Math.round(Math.random());
if (temp > 0.5) {
resolve(temp);
} else {
reject(temp);
}
}, 2000);
});
};
start()
.then((res) => {
console.log("res", res);
})
.catch((err) => {
console.log("err", err);
})
.myFinally(() => {
console.log("finally");
});
Promise.prototype.finally = function (callback) { let P = this.constructor; return this.then( value => { callback(); return value; }, reason => { callback(); throw reason } ); };为什么需要Promise.resolve(callback()).then(() => value) 而不能直接执行callback, return value 你这个不能处理异步情况
看了这个问题才知道,原来 promise 的 finally 只是不管成功还是失败都会执行而已,而不会永远最后执行joy
new Promise((resolve, reject) => { resolve(); }).finally(() => { console.log('finally1'); }).then(() => { console.log('then'); }).finally(() => { console.log('finally2'); });finally1 then finally2
你不说,我都没仔细注意到。。。
Promise.prototype.finally = function (callback) {
return this.then(
r => Promise.resolve(callback()).then(() => r),
e => Promise.resolve(callback()).then(() => { throw e })
)
}
看了这个问题才知道,原来 promise 的 finally 只是不管成功还是失败都会执行而已,而不会永远最后执行😂
new Promise((resolve, reject) => { resolve(); }).finally(() => { console.log('finally1'); }).then(() => { console.log('then'); }).finally(() => { console.log('finally2'); });finally1 then finally2
你不说,我都没注意到,招你这样说,这就是个普通函数而已
这样应该没什么问题吧,直接this也不用管是引入的还是默认的,cb也简单处理了一下,也能传递数据或者错误
Promise.prototype.finally = function(cb) {
cb = typeof cb === 'function' ? cb : () => cb
return this.then(cb, cb)
}