- 发布于
如何判断一个值是否为 Promise
- 作者
- 姓名
- Jacob
Promise 是如何创建的
我们的目的是要判断一个值是否为 Promise
,那我们不妨先看下 Promise 对象是如何创建的
const test = new Promise((resolve) => {
setTimeout(() => {
resolve('success')
}, 2000)
})
test.then((res) => {
console.log(res)
})
上述代码会在 2s 之后输出 success
。由此我们可以看出 test
是 Promise
创建的一个实例,我们可以画出以下原型链示意图:
既然 test
的 __proto__
指向 Promise.prototype
,那我们能不能用 instanceOf
呢?
instanceOf ??
首先来看下 instanceOf
函数的定义:
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
因为 test
的 __proto__
指向 Promise.prototype
,所以原理上使用 instanceOf
是可行的:
// test 为上述代码块中创建的 test 变量
test instanceof Promise
以上代码校验结果为 true
。是不是之后可以用这种方式判定呢?答案是不可以,因为有一种特殊情况,我们常用的 Promise
是 ES6 对 Promise/A+
的一种实现,开源社区中的一些库是自己实现的,比如 bluebird
。所以我们使用 ES6 原生 Promise 去校验 bluebird
的话肯定是校验不通过的。
import { Promise as BluebirdPromise } from 'bluebird'
const test = new BluebirdPromise((resolve) => resolve('success'))
console.log(test instanceof Promise) // 输出为 false
console.log(test instanceof bluebirdPromise) // 输出为 true
直接判断是否有 then ??
既然我们不能直接使用 instanceOf
判断的话,我们是有可以判断值是否有 then
呢?
根据一个值的形态(具有哪些属性)对这个值的类型做出一些假定。这种类型检查一般用术语 鸭子类型 来表示 —— 「如果它看起来像只鸭子,叫起来相纸鸭子,那它一定就是只鸭子」。
那么我们可以写出以下代码:
if (
p !== null &&
(typeof p === 'object' || typeof p === 'function') &&
typeof p.then === 'function'
) {
// 那么这个值为 thenable
}
但是这种方式判断确实会导致一些问题,比如一个对象中恰好定义了一个 then
函数,但其并不是表示 Promise 或者 thenable。
class Test {
then() {
console.log('命名冲突!')
}
}
是不是不需要判断呢?
我们可以直接使用 Promise.resolve()
来处理未知的值,代码如下:
Promise.resolve(valueOrPromiseItDoesntMatter).then((value) => {
console.log(value)
})
Promise.resolve()
中可以对 Promise 和 thenable 做处理,不需要我们做额外判断,可以说是一个比较完美的处理方式了。
参考文献:
- You Don't Know JavaScript: Async & Performance by Kyle Simpson (O'Reilly). Copyright 2015 Getify Solutions, Inc., 978-1-491-90419-0
- instanceof - MDN
- How do I tell if an object is a Promise? - stackOverflow