Skip to content

Commit

Permalink
feat(tool function): add autoPolyfill()
Browse files Browse the repository at this point in the history
  • Loading branch information
calimanco committed Dec 29, 2020
1 parent 0d434f7 commit 72e8e45
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 29 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ if (global && typeof global.Promise !== 'function') {
- 可自定义 Promise 实现,直接扩展已有的 Promise 构造函数。
- 工具函数
- [x] initPromise()
- [ ] autoPolyfill()
- [x] autoPolyfill()
- 静态方法
- [x] Promise.all()
- [x] Promise.race()
Expand Down Expand Up @@ -104,7 +104,15 @@ const PromisePlus = initPromise(CustomPromise)

#### autoPolyfill()

// TODO
自动对当前运行环境进行 Promise Polyfill。
如果全局没有 Promise 支持,则会直接将内置的 Promise 实现挂载到全局;
如果全局已有 Promise 支持,则会对现有的 Promise 进行扩展后挂载到全局。

```javascript
import { autoPolyfill } from 'promise-polyfill-plus'

autoPolyfill()
```

### 静态方法

Expand Down
12 changes: 10 additions & 2 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ if (global && typeof global.Promise !== 'function') {
- It can customize promise implementation and directly extend existing promise constructors.
- Tool function
- [x] initPromise()
- [ ] autoPolyfill()
- [x] autoPolyfill()
- Static method
- [x] Promise.all()
- [x] Promise.race()
Expand Down Expand Up @@ -103,7 +103,15 @@ const PromisePlus = initPromise(CustomPromise)

#### autoPolyfill()

// TODO
Promise polyfill for the current operating environment automatically.
If there is no global Promise support, the built-in Promise will be directly mounted to the global;
If there is global Promise support, the existing Promise will be expanded and mounted to the global.

```javascript
import { autoPolyfill } from 'promise-polyfill-plus'

autoPolyfill()
```

### Static method

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"husky": "^4.3.6",
"jest": "^26.6.3",
"jest-config": "^26.6.3",
"jest-environment-node": "^26.6.2",
"lint-staged": "^10.5.3",
"lodash.camelcase": "^4.3.0",
"prettier": "^2.2.1",
Expand Down
20 changes: 20 additions & 0 deletions src/helpers/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,26 @@ export function isPromiseLike(val: any): val is PromiseLike<any> {
)
}

/**
* 判断是否是 PromiseConstructorLike 的对象。
* @param promiseClass
*/
export function isPromiseConstructorLike(
promiseClass: any
): promiseClass is PromiseConstructorLike {
try {
const instance = new promiseClass(() => {
// do nothing
})
if (!isPromiseLike(instance)) {
return false
}
} catch (err) {
return false
}
return true
}

/**
* 判断是否是内置的 Promise 构造函数产生的 promise 对象。
* @param val 需要判断的对象
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Promise from './promise-polyfill-plus'
export * from './types'

// 导出构建方法
export { initPromise } from './promise-polyfill-plus'
export { initPromise, autoPolyfill } from './promise-polyfill-plus'

// 导出主体
export default Promise
29 changes: 17 additions & 12 deletions src/promise-polyfill-plus.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { MyPromiseStatic } from './types'
import { isPromiseLike } from './helpers/util'
import { isPromiseConstructorLike } from './helpers/util'
import MyPromise from './core/MyPromise'
import initAll from './lib/all'
import initRace from './lib/race'
Expand All @@ -26,17 +26,10 @@ const staticMethods = {
* @param promiseClass
*/
export function initPromise(promiseClass: PromiseConstructorLike) {
try {
const instance = new promiseClass(() => {
// do nothing
})
if (!isPromiseLike(instance)) {
throw new TypeError(
`Init param ${promiseClass} is not a PromiseConstructorLike object`
)
}
} catch (err) {
throw err
if (!isPromiseConstructorLike(promiseClass)) {
throw new TypeError(
`Init param ${promiseClass} is not a PromiseConstructorLike object`
)
}
Object.keys(staticMethods).forEach(key => {
if (typeof (promiseClass as any)[key] !== 'function') {
Expand All @@ -48,4 +41,16 @@ export function initPromise(promiseClass: PromiseConstructorLike) {

const Promise = initPromise(MyPromise)

/**
* 自动 Polyfill 当前运行环境的 Promise
*/
export function autoPolyfill() {
const env = typeof window !== 'undefined' ? window : global
if (env.Promise && isPromiseConstructorLike(env.Promise)) {
;(env as any).Promise = initPromise(env.Promise)
} else {
;(env as any).Promise = Promise
}
}

export default Promise
32 changes: 22 additions & 10 deletions test/MyPromise-init.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import MyPromise, { initPromise } from '../src/index'
import MyPromise, { initPromise, autoPolyfill } from '../src/index'

/**
* 实例化测试
Expand Down Expand Up @@ -50,17 +50,29 @@ describe('init function test', () => {
})

it('should not be added method', () => {
const newPromise = initPromise(Promise)
expect(newPromise.all).not.toEqual(MyPromise.all)
expect(newPromise.race).not.toEqual(MyPromise.race)
expect(newPromise.resolve).not.toEqual(MyPromise.resolve)
expect(newPromise.reject).not.toEqual(MyPromise.reject)
const newPromiseClass = initPromise(Promise)
expect(newPromiseClass.all).not.toEqual(MyPromise.all)
expect(newPromiseClass.race).not.toEqual(MyPromise.race)
expect(newPromiseClass.resolve).not.toEqual(MyPromise.resolve)
expect(newPromiseClass.reject).not.toEqual(MyPromise.reject)
})

it('should be added method', () => {
const newPromise = initPromise(Promise)
expect(newPromise.deferred).not.toBeUndefined()
expect(newPromise.allSettled).not.toBeUndefined()
expect(newPromise.try).not.toBeUndefined()
const newPromiseClass = initPromise(Promise)
expect(newPromiseClass.deferred).not.toBeUndefined()
expect(newPromiseClass.allSettled).not.toBeUndefined()
expect(newPromiseClass.any).not.toBeUndefined()
expect(newPromiseClass.try).not.toBeUndefined()
})
})

describe('init function test', () => {
it('should be added method', () => {
autoPolyfill()
const EnvPromise: any = Promise
expect(EnvPromise.deferred).not.toBeUndefined()
expect(EnvPromise.allSettled).not.toBeUndefined()
expect(EnvPromise.any).not.toBeUndefined()
expect(EnvPromise.try).not.toBeUndefined()
})
})
19 changes: 19 additions & 0 deletions test/env/no-promise-environment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// no-promise-environment
const NodeEnvironment = require('jest-environment-node')

class NoPromiseEnvironment extends NodeEnvironment {
constructor(config, context) {
super(config, context)
this.testPath = context.testPath
this.docblockPragmas = context.docblockPragmas
}
async setup() {
await super.setup()

setTimeout(()=>{
this.global.Promise = undefined
})
}
}

module.exports = NoPromiseEnvironment
19 changes: 19 additions & 0 deletions test/no_promise_env.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* @jest-environment ./test/env/no-promise-environment
*/

import { autoPolyfill } from '../src'

describe('init function test in no promise env', () => {
it('should be added method', done => {
setTimeout(() => {
autoPolyfill()
const EnvPromise: any = Promise
expect(EnvPromise.deferred).not.toBeUndefined()
expect(EnvPromise.allSettled).not.toBeUndefined()
expect(EnvPromise.any).not.toBeUndefined()
expect(EnvPromise.try).not.toBeUndefined()
done()
})
})
})

0 comments on commit 72e8e45

Please sign in to comment.