完整API
Promise是一个类
- JS里类是一种特殊的函数
- 类属性length(可忽略)其实就是几个参数
- 类方法:all/allSettled/race/reject/resolve
- 对象属性:then(重要)/finally/catch
- 对象的内部属性:state=pending/fulfilled/rejected
API的规则
- Promise/A+ 规格文档
- 按照上面的文档写测试用例
-
代码
使用chai
$ yarn init -y
$ yarn global add ts-node mocha
$ yarn add chai mocha --dev
$ yarn add @types/chai @types/mocha --dev
- 创建test/index.ts
$ mocha -r ts-node/register test/index.ts
将ts和ts-node安装到本地
$ yarn add --dev typescript ts-node
- 写成脚本命令
package.json
{
...
"scripts": {
"test": "mocha -r ts-node/register test/**/*.ts"
},
...
}
异步测试
src/promise.ts
class Promise2 {
succeed = null
fail = null
resolve() {
setTimeout(() => { this.succeed() }, 0)
}
reject() {
setTimeout(() => { this.fail() }, 0)
}
constructor(fn) {
if (typeof fn !== 'function') {
throw new Error("只接受函数")
}
fn(this.resolve.bind(this), this.reject.bind(this))
}
then(succeed, fail) {
this.succeed = succeed
this.fail = fail
}
}
export default Promise2
test/index.ts
import * as chai from 'chai'
const assert = chai.assert
import Promise from "../src/promise"
describe('Promise', () => {
it("Promise是一个类", () => {
assert.isFunction(Promise)
assert.isObject(Promise.prototype)
})
it("new Promise() 如果接受不是一个函数就报错", () => {
assert.throw(() => {
//@ts-ignore
new Promise()
})
assert.throw(() => {
//@ts-ignore
new Promise(1)
})
assert.throw(() => {
//@ts-ignore
new Promise(false)
})
})
it('new Promise(fn) 会生成一个对象,对象有then方法', () => {
const promise = new Promise(() => { })
assert.isFunction(promise.then)
})
it('new Promise(fn)中的fn立即执行', () => {
let called = false
const promise = new Promise(() => {
called = true
})
//@ts-ignore
assert(called === true)
})
it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', () => {
let called = false
const promise = new Promise((resolve,reject) => {
called = true
assert.isFunction(resolve)
assert.isFunction(reject)
})
//@ts-ignore
assert(called === true)
})
it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
let called=false;
const promise = new Promise((resolve,reject) => {
//该函数没有执行
assert(called===false)
resolve()
//该函数执行了
setTimeout(() => {
assert(called===true)
done()
});
})
//@ts-ignore
promise.then(()=>{
called=true
},()=>{})
})
});
使用sinon测试函数
安装
$ yarn add --dev sinon sinon-chai
$ yarn add --dev @types/sinon @types/sinon-chai
...
import * as sinon from 'sinon'
import * as sinonChai from 'sinon-chai'
chai.use(sinonChai)
...
describe('Promise', () => {
...
it('new Promise(fn)中的fn立即执行', () => {
let fn = sinon.fake()
new Promise(fn)
assert(fn.called)
})
it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
const success = sinon.fake()
const promise = new Promise((resolve, reject) => {
//该函数没有执行
assert.isFalse(success.called)
resolve()
//该函数执行了
setTimeout(() => {
assert.isTrue(success.called)
done()
});
})
//@ts-ignore
promise.then(success)
})
})
根据Promise A+规范
/src/promise.ts
class Promise2 {
state = "pending"
callBacks = []
resolve(result) {
if (this.state !== 'pending') return;
this.state = 'fulfilled'
setTimeout(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[0] === 'function') {
handle[0].call(undefined, result)
}
})
}, 0)
}
reject(reason) {
if (this.state !== 'pending') return;
this.state = 'rejected'
setTimeout(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[1] === 'function') {
handle[1].call(undefined, reason)
}
})
}, 0)
}
constructor(fn) {
if (typeof fn !== 'function') {
throw new Error("只接受函数")
}
fn(this.resolve.bind(this), this.reject.bind(this))
}
then(succeed?, fail?) {
const handle = []
if (typeof succeed === 'function') {
handle[0] = succeed
}
if (typeof fail === 'function') {
handle[1] = fail
}
this.callBacks.push(handle)
}
}
export default Promise2
/test/index.ts
import * as chai from 'chai'
import * as sinon from 'sinon'
import * as sinonChai from 'sinon-chai'
chai.use(sinonChai)
const assert = chai.assert
import Promise from "../src/promise"
describe('Promise', () => {
it("Promise是一个类", () => {
assert.isFunction(Promise)
assert.isObject(Promise.prototype)
})
it("new Promise() 如果接受不是一个函数就报错", () => {
assert.throw(() => {
//@ts-ignore
new Promise()
})
assert.throw(() => {
//@ts-ignore
new Promise(1)
})
assert.throw(() => {
//@ts-ignore
new Promise(false)
})
})
it('new Promise(fn) 会生成一个对象,对象有then方法', () => {
const promise = new Promise(() => { })
assert.isFunction(promise.then)
})
it('new Promise(fn)中的fn立即执行', () => {
let fn = sinon.fake()
new Promise(fn)
assert(fn.called)
})
it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', (done) => {
new Promise((resolve, reject) => {
assert.isFunction(resolve)
assert.isFunction(reject)
done()
})
})
it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
const success = sinon.fake()
const promise = new Promise((resolve, reject) => {
//该函数没有执行
assert.isFalse(success.called)
resolve()
//该函数执行了
setTimeout(() => {
assert.isTrue(success.called)
done()
});
})
//@ts-ignore
promise.then(success)
})
it('promise.then(null,fail)中的fail会在reject被调用的时候执行', (done) => {
const fail = sinon.fake()
const promise = new Promise((resolve, reject) => {
//该函数没有执行
assert.isFalse(fail.called)
reject()
//该函数执行了
setTimeout(() => {
assert.isTrue(fail.called)
done()
});
})
//@ts-ignore
promise.then(null, fail)
})
it('2.2.1onFulfilled和onRejected都是可选的参数', () => {
const promise = new Promise((resolve) => {
resolve()
})
promise.then(false, null)
assert(1 === 1)
});
it('2.2.2如果onFulfilled是函数', (done) => {
const succeed = sinon.fake()
const promise = new Promise((resolve) => {
assert.isFalse(succeed.called)
resolve(233)
resolve(2333)
setTimeout(() => {
assert(promise.state === 'fulfilled')
assert.isTrue(succeed.calledOnce)
assert(succeed.calledWith(233))
done()
}, 0);
})
promise.then(succeed)
});
it('2.2.3如果onRejected是函数', (done) => {
const fail = sinon.fake()
const promise = new Promise((resolve, reject) => {
assert.isFalse(fail.called)
reject(233)
reject(2333)
setTimeout(() => {
assert(promise.state === 'rejected')
assert.isTrue(fail.calledOnce)
assert(fail.calledWith(233))
done()
}, 0);
})
promise.then(null, fail)
});
it('2.2.4在我的代码完成之前不得调用then后面的成功函数', (done) => {
const succeed = sinon.fake()
const promise = new Promise((resolve) => {
resolve()
})
promise.then(succeed)
assert.isFalse(succeed.called)
setTimeout(() => {
assert.isTrue(succeed.called)
done()
}, 0);
});
it('2.2.4在我的代码完成之前不得调用then后面的失败函数', (done) => {
const fn = sinon.fake()
const promise = new Promise((resolve, reject) => {
reject()
})
promise.then(null, fn)
assert.isFalse(fn.called)
setTimeout(() => {
assert.isTrue(fn.called)
done()
}, 0);
});
it("2.2.5", (done) => {
const promise = new Promise(resolve => {
resolve()
})
promise.then(function () {
"use strict"
assert(this === undefined)
done()
})
})
it("2.2.6 then成功可以在同一个promise里被多次调用", (done) => {
const promise = new Promise((resolve) => {
resolve()
})
const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
promise.then(callBacks[0])
promise.then(callBacks[1])
promise.then(callBacks[2])
setTimeout(() => {
assert(callBacks[0].called)
assert(callBacks[1].calledAfter(callBacks[0]))
assert(callBacks[2].calledAfter(callBacks[1]))
done()
}, 0);
})
it("2.2.6.2 then失败可以在同一个promise里被多次调用", (done) => {
const promise = new Promise((resolve, reject) => {
reject()
})
const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
promise.then(null, callBacks[0])
promise.then(null, callBacks[1])
promise.then(null, callBacks[2])
setTimeout(() => {
assert(callBacks[0].called)
assert(callBacks[1].calledAfter(callBacks[0]))
assert(callBacks[2].calledAfter(callBacks[1]))
done()
}, 0);
})
});
Promise解决程序
/src/promise.ts
class Promise2 {
state = "pending"
callBacks = []
resolve(result) {
if (this.state !== 'pending') return;
this.state = 'fulfilled'
setTimeout(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[0] === 'function') {
const x = handle[0].call(undefined, result)
handle[2].resolveWith(x)
}
})
}, 0)
}
reject(reason) {
if (this.state !== 'pending') return;
this.state = 'rejected'
setTimeout(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[1] === 'function') {
const x = handle[1].call(undefined, reason)
handle[2].resolveWith(x)
}
})
}, 0)
}
constructor(fn) {
if (typeof fn !== 'function') {
throw new Error("只接受函数")
}
fn(this.resolve.bind(this), this.reject.bind(this))
}
then(succeed?, fail?) {
const handle = []
if (typeof succeed === 'function') {
handle[0] = succeed
}
if (typeof fail === 'function') {
handle[1] = fail
}
handle[2] = new Promise2(() => { })
this.callBacks.push(handle)
return handle[2]
}
//2.2.7.1
resolveWith(x) {
//2.3.1 如果promise和x引用同一个对象,则用TypeError作为原因拒绝(reject)promise。
if (this === x) {
this.reject(new TypeError())
} else if (x instanceof Promise2) {//2.3.2 如果x是一个promise,采用promise的状态3.4
x.then((result) => {
this.resolve(result)
}, (reason) => {
this.reject(reason)
})
}
//2.3.3另外,如果x是个对象或者方法
if (x instanceof Object) {
let then
try {
then = x.then
} catch (error) {
this.reject(error)
}
if (then instanceof Function) {
try {
x.then((y) => {
this.resolveWith(y)
}, (r) => {
this.reject(r)
})
} catch (error) {
this.reject(error)
}
} else {
this.resolve(x)
}
} else {
this.resolve(x)
}
}
}
export default Promise2
/test/index.ts
import * as chai from 'chai'
import * as sinon from 'sinon'
import * as sinonChai from 'sinon-chai'
chai.use(sinonChai)
const assert = chai.assert
import Promise from "../src/promise"
describe('Promise', () => {
it("Promise是一个类", () => {
assert.isFunction(Promise)
assert.isObject(Promise.prototype)
})
it("new Promise() 如果接受不是一个函数就报错", () => {
assert.throw(() => {
//@ts-ignore
new Promise()
})
assert.throw(() => {
//@ts-ignore
new Promise(1)
})
assert.throw(() => {
//@ts-ignore
new Promise(false)
})
})
it('new Promise(fn) 会生成一个对象,对象有then方法', () => {
const promise = new Promise(() => { })
assert.isFunction(promise.then)
})
it('new Promise(fn)中的fn立即执行', () => {
let fn = sinon.fake()
new Promise(fn)
assert(fn.called)
})
it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', (done) => {
new Promise((resolve, reject) => {
assert.isFunction(resolve)
assert.isFunction(reject)
done()
})
})
it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
const success = sinon.fake()
const promise = new Promise((resolve, reject) => {
//该函数没有执行
assert.isFalse(success.called)
resolve()
//该函数执行了
setTimeout(() => {
assert.isTrue(success.called)
done()
});
})
//@ts-ignore
promise.then(success)
})
it('promise.then(null,fail)中的fail会在reject被调用的时候执行', (done) => {
const fail = sinon.fake()
const promise = new Promise((resolve, reject) => {
//该函数没有执行
assert.isFalse(fail.called)
reject()
//该函数执行了
setTimeout(() => {
assert.isTrue(fail.called)
done()
});
})
//@ts-ignore
promise.then(null, fail)
})
it('2.2.1onFulfilled和onRejected都是可选的参数', () => {
const promise = new Promise((resolve) => {
resolve()
})
promise.then(false, null)
assert(1 === 1)
});
it('2.2.2如果onFulfilled是函数', (done) => {
const succeed = sinon.fake()
const promise = new Promise((resolve) => {
assert.isFalse(succeed.called)
resolve(233)
resolve(2333)
setTimeout(() => {
assert(promise.state === 'fulfilled')
assert.isTrue(succeed.calledOnce)
assert(succeed.calledWith(233))
done()
}, 0);
})
promise.then(succeed)
});
it('2.2.3如果onRejected是函数', (done) => {
const fail = sinon.fake()
const promise = new Promise((resolve, reject) => {
assert.isFalse(fail.called)
reject(233)
reject(2333)
setTimeout(() => {
assert(promise.state === 'rejected')
assert.isTrue(fail.calledOnce)
assert(fail.calledWith(233))
done()
}, 0);
})
promise.then(null, fail)
});
it('2.2.4在我的代码完成之前不得调用then后面的成功函数', (done) => {
const succeed = sinon.fake()
const promise = new Promise((resolve) => {
resolve()
})
promise.then(succeed)
assert.isFalse(succeed.called)
setTimeout(() => {
assert.isTrue(succeed.called)
done()
}, 0);
});
it('2.2.4在我的代码完成之前不得调用then后面的失败函数', (done) => {
const fn = sinon.fake()
const promise = new Promise((resolve, reject) => {
reject()
})
promise.then(null, fn)
assert.isFalse(fn.called)
setTimeout(() => {
assert.isTrue(fn.called)
done()
}, 0);
});
it("2.2.5", (done) => {
const promise = new Promise(resolve => {
resolve()
})
promise.then(function () {
"use strict"
assert(this === undefined)
done()
})
})
it("2.2.6 then成功可以在同一个promise里被多次调用", (done) => {
const promise = new Promise((resolve) => {
resolve()
})
const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
promise.then(callBacks[0])
promise.then(callBacks[1])
promise.then(callBacks[2])
setTimeout(() => {
assert(callBacks[0].called)
assert(callBacks[1].calledAfter(callBacks[0]))
assert(callBacks[2].calledAfter(callBacks[1]))
done()
}, 0);
})
it("2.2.6.2 then失败可以在同一个promise里被多次调用", (done) => {
const promise = new Promise((resolve, reject) => {
reject()
})
const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
promise.then(null, callBacks[0])
promise.then(null, callBacks[1])
promise.then(null, callBacks[2])
setTimeout(() => {
assert(callBacks[0].called)
assert(callBacks[1].calledAfter(callBacks[0]))
assert(callBacks[2].calledAfter(callBacks[1]))
done()
}, 0);
})
it("2.2.7 then必须返回一个promise", () => {
const promise = new Promise((resolve) => {
resolve()
})
const promise2 = promise.then(() => { }, () => { })
assert(promise2 instanceof Promise)
})
it("2.2.7.1 如果then(sucess,fail)中的success返回一个值x,运行[[Resolve]](promise2, x)", (done) => {
const promise1 = new Promise((resolve) => {
resolve()
})
promise1.then(() => "成功", () => { }).then(result => {
assert.equal(result, "成功")
done()
})
})
it("2.2.7.1.2 x是一个promise实例", (done) => {
const promise1 = new Promise((resolve) => {
resolve()
})
const fn = sinon.fake()
const promise2 = promise1.then(() => new Promise(resolve => resolve()))
promise2.then(fn)
setTimeout(() => {
assert(fn.called)
done()
}, 1000);
})
});
宏任务与微任务
setTimeout改用process.nextTick$ yarn add @types/node --dev
/tsconfig.json
{
"compilerOptions": {
"types": [
"node",
"mocha"
]
}
}
/src/promise.ts
class Promise2 {
state = "pending"
callBacks = []
resolve(result) {
if (this.state !== 'pending') return;
this.state = 'fulfilled'
process.nextTick(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[0] === 'function') {
let x
try {
x = handle[0].call(undefined, result)
} catch (e) {
return handle[2].reject(e)
}
handle[2].resolveWith(x)
}
})
})
}
reject(reason) {
if (this.state !== 'pending') return;
this.state = 'rejected'
process.nextTick(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[1] === 'function') {
let x
try {
x = handle[1].call(undefined, reason)
} catch (e) {
return handle[2].reject(e)
}
handle[2].resolveWith(x)
}
})
})
}
constructor(fn) {
if (typeof fn !== 'function') {
throw new Error("只接受函数")
}
fn(this.resolve.bind(this), this.reject.bind(this))
}
then(succeed?, fail?) {
const handle = []
if (typeof succeed === 'function') {
handle[0] = succeed
}
if (typeof fail === 'function') {
handle[1] = fail
}
handle[2] = new Promise2(() => { })
this.callBacks.push(handle)
return handle[2]
}
//2.2.7.1
resolveWith(x) {
//2.3.1 如果promise和x引用同一个对象,则用TypeError作为原因拒绝(reject)promise。
if (this === x) {
this.reject(new TypeError())
} else if (x instanceof Promise2) {//2.3.2 如果x是一个promise,采用promise的状态3.4
x.then((result) => {
this.resolve(result)
}, (reason) => {
this.reject(reason)
})
}
//2.3.3另外,如果x是个对象或者方法
if (x instanceof Object) {
let then
try {
then = x.then
} catch (error) {
this.reject(error)
}
if (then instanceof Function) {
try {
x.then((y) => {
this.resolveWith(y)
}, (r) => {
this.reject(r)
})
} catch (error) {
this.reject(error)
}
} else {
this.resolve(x)
}
} else {
this.resolve(x)
}
}
}
export default Promise2
浏览器模拟nextTick
因为process.nextTick只存在node中,如何让浏览器也支持
MutationObserver
/src/promise.ts
class Promise2 {
state = "pending"
callBacks = []
resolve(result) {
if (this.state !== 'pending') return;
this.state = 'fulfilled'
nextTick(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[0] === 'function') {
let x
try {
x = handle[0].call(undefined, result)
} catch (e) {
return handle[2].reject(e)
}
handle[2].resolveWith(x)
}
})
})
}
reject(reason) {
if (this.state !== 'pending') return;
this.state = 'rejected'
nextTick(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[1] === 'function') {
let x
try {
x = handle[1].call(undefined, reason)
} catch (e) {
return handle[2].reject(e)
}
handle[2].resolveWith(x)
}
})
})
}
constructor(fn) {
if (typeof fn !== 'function') {
throw new Error("只接受函数")
}
fn(this.resolve.bind(this), this.reject.bind(this))
}
then(succeed?, fail?) {
const handle = []
if (typeof succeed === 'function') {
handle[0] = succeed
}
if (typeof fail === 'function') {
handle[1] = fail
}
handle[2] = new Promise2(() => { })
this.callBacks.push(handle)
return handle[2]
}
//2.2.7.1
resolveWith(x) {
//2.3.1 如果promise和x引用同一个对象,则用TypeError作为原因拒绝(reject)promise。
if (this === x) {
this.reject(new TypeError())
} else if (x instanceof Promise2) {//2.3.2 如果x是一个promise,采用promise的状态3.4
x.then((result) => {
this.resolve(result)
}, (reason) => {
this.reject(reason)
})
}
//2.3.3另外,如果x是个对象或者方法
if (x instanceof Object) {
let then
try {
then = x.then
} catch (error) {
this.reject(error)
}
if (then instanceof Function) {
try {
x.then((y) => {
this.resolveWith(y)
}, (r) => {
this.reject(r)
})
} catch (error) {
this.reject(error)
}
} else {
this.resolve(x)
}
} else {
this.resolve(x)
}
}
}
export default Promise2
function nextTick(fn) {
if (process !== undefined && typeof process.nextTick === 'function') {
return process.nextTick(fn)
}
var counter = 1
var observer = new MutationObserver(fn)
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
counter = (counter + 1) % 2
textNode.data = String(counter)
}
最终版本
优化代码
/src/promise.ts
class Promise2 {
state = "pending"
callBacks = []
private resolveOrReject(state, data, i) {
if (this.state !== 'pending') return;
this.state = state
nextTick(() => {
this.callBacks.forEach((handle) => {
if (typeof handle[i] === 'function') {
let x
try {
x = handle[i].call(undefined, data)
} catch (e) {
return handle[2].reject(e)
}
handle[2].resolveWith(x)
}
})
})
}
resolve(result) {
this.resolveOrReject('fulfilled', result, 0)
}
reject(reason) {
this.resolveOrReject('rejected', reason, 1)
}
constructor(fn) {
if (typeof fn !== 'function') {
throw new Error("只接受函数")
}
fn(this.resolve.bind(this), this.reject.bind(this))
}
then(succeed?, fail?) {
const handle = []
if (typeof succeed === 'function') {
handle[0] = succeed
}
if (typeof fail === 'function') {
handle[1] = fail
}
handle[2] = new Promise2(() => { })
this.callBacks.push(handle)
return handle[2]
}
private resolveWithSelf() {
this.reject(new TypeError())
}
private resolveWithPromise(x) {
x.then((result) => {
this.resolve(result)
}, (reason) => {
this.reject(reason)
})
}
private getThen(x) {
let then
try {
then = x.then
} catch (error) {
return this.reject(error)
}
return then
}
private resolveWithThenable(x) {
try {
x.then(y => {
this.resolveWith(y)
}, r => {
this.reject(r)
})
} catch (error) {
this.reject(error)
}
}
private resolveWithObject(x) {
let then = this.getThen(x)
if (then instanceof Function) {
this.resolveWithThenable(x)
} else {
this.resolve(x)
}
}
resolveWith(x) {
//2.3.1 如果promise和x引用同一个对象,则用TypeError作为原因拒绝(reject)promise。
if (this === x) {
this.resolveWithSelf()
} else if (x instanceof Promise2) {
this.resolveWithPromise(x)
} else if (x instanceof Object) {
this.resolveWithObject(x)
} else {
this.resolve(x)
}
}
}
export default Promise2
function nextTick(fn) {
if (process !== undefined && typeof process.nextTick === 'function') {
return process.nextTick(fn)
}
var counter = 1
var observer = new MutationObserver(fn)
var textNode = document.createTextNode(String(counter))
observer.observe(textNode, {
characterData: true
})
counter = (counter + 1) % 2
textNode.data = String(counter)
}
最终测试代码
/test/index.ts
import * as chai from 'chai'
import * as sinon from 'sinon'
import * as sinonChai from 'sinon-chai'
chai.use(sinonChai)
const assert = chai.assert
import Promise from "../src/promise"
describe('Promise', () => {
it("Promise是一个类", () => {
assert.isFunction(Promise)
assert.isObject(Promise.prototype)
})
it("new Promise() 如果接受不是一个函数就报错", () => {
assert.throw(() => {
//@ts-ignore
new Promise()
})
assert.throw(() => {
//@ts-ignore
new Promise(1)
})
assert.throw(() => {
//@ts-ignore
new Promise(false)
})
})
it('new Promise(fn) 会生成一个对象,对象有then方法', () => {
const promise = new Promise(() => { })
assert.isFunction(promise.then)
})
it('new Promise(fn)中的fn立即执行', () => {
let fn = sinon.fake()
new Promise(fn)
assert(fn.called)
})
it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', (done) => {
new Promise((resolve, reject) => {
assert.isFunction(resolve)
assert.isFunction(reject)
done()
})
})
it('promise.then(success)中的success会在resoleve被调用的时候执行', (done) => {
const success = sinon.fake()
const promise = new Promise((resolve, reject) => {
//该函数没有执行
assert.isFalse(success.called)
resolve()
//该函数执行了
setTimeout(() => {
assert.isTrue(success.called)
done()
});
})
//@ts-ignore
promise.then(success)
})
it('promise.then(null,fail)中的fail会在reject被调用的时候执行', (done) => {
const fail = sinon.fake()
const promise = new Promise((resolve, reject) => {
//该函数没有执行
assert.isFalse(fail.called)
reject()
//该函数执行了
setTimeout(() => {
assert.isTrue(fail.called)
done()
});
})
//@ts-ignore
promise.then(null, fail)
})
it('2.2.1onFulfilled和onRejected都是可选的参数', () => {
const promise = new Promise((resolve) => {
resolve()
})
promise.then(false, null)
assert(1 === 1)
});
it('2.2.2如果onFulfilled是函数', (done) => {
const succeed = sinon.fake()
const promise = new Promise((resolve) => {
assert.isFalse(succeed.called)
resolve(233)
resolve(2333)
setTimeout(() => {
assert(promise.state === 'fulfilled')
assert.isTrue(succeed.calledOnce)
assert(succeed.calledWith(233))
done()
}, 0);
})
promise.then(succeed)
});
it('2.2.3如果onRejected是函数', (done) => {
const fail = sinon.fake()
const promise = new Promise((resolve, reject) => {
assert.isFalse(fail.called)
reject(233)
reject(2333)
setTimeout(() => {
assert(promise.state === 'rejected')
assert.isTrue(fail.calledOnce)
assert(fail.calledWith(233))
done()
}, 0);
})
promise.then(null, fail)
});
it('2.2.4在我的代码完成之前不得调用then后面的成功函数', (done) => {
const succeed = sinon.fake()
const promise = new Promise((resolve) => {
resolve()
})
promise.then(succeed)
assert.isFalse(succeed.called)
setTimeout(() => {
assert.isTrue(succeed.called)
done()
}, 0);
});
it('2.2.4在我的代码完成之前不得调用then后面的失败函数', (done) => {
const fn = sinon.fake()
const promise = new Promise((resolve, reject) => {
reject()
})
promise.then(null, fn)
assert.isFalse(fn.called)
setTimeout(() => {
assert.isTrue(fn.called)
done()
}, 0);
});
it("2.2.5", (done) => {
const promise = new Promise(resolve => {
resolve()
})
promise.then(function () {
"use strict"
assert(this === undefined)
done()
})
})
it("2.2.6 then成功可以在同一个promise里被多次调用", (done) => {
const promise = new Promise((resolve) => {
resolve()
})
const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
promise.then(callBacks[0])
promise.then(callBacks[1])
promise.then(callBacks[2])
setTimeout(() => {
assert(callBacks[0].called)
assert(callBacks[1].calledAfter(callBacks[0]))
assert(callBacks[2].calledAfter(callBacks[1]))
done()
}, 0);
})
it("2.2.6.2 then失败可以在同一个promise里被多次调用", (done) => {
const promise = new Promise((resolve, reject) => {
reject()
})
const callBacks = [sinon.fake(), sinon.fake(), sinon.fake()]
promise.then(null, callBacks[0])
promise.then(null, callBacks[1])
promise.then(null, callBacks[2])
setTimeout(() => {
assert(callBacks[0].called)
assert(callBacks[1].calledAfter(callBacks[0]))
assert(callBacks[2].calledAfter(callBacks[1]))
done()
}, 0);
})
it("2.2.7 then必须返回一个promise", () => {
const promise = new Promise((resolve) => {
resolve()
})
const promise2 = promise.then(() => { }, () => { })
assert(promise2 instanceof Promise)
})
it("2.2.7.1 如果then(sucess,fail)中的success返回一个值x,运行[[Resolve]](promise2, x)", (done) => {
const promise1 = new Promise((resolve) => {
resolve()
})
promise1.then(() => "成功", () => { }).then(result => {
assert.equal(result, "成功")
done()
})
})
it("2.2.7.1.2 success的返回值是一个promise实例", (done) => {
const promise1 = new Promise((resolve) => {
resolve()
})
const fn = sinon.fake()
const promise2 = promise1.then(() => new Promise(resolve => resolve()))
promise2.then(fn)
setTimeout(() => {
assert(fn.called)
done()
}, 0);
})
it("2.2.7.1.2 success的返回值是一个promise实例,且失败了", (done) => {
const promise1 = new Promise((resolve) => {
resolve()
})
const fn = sinon.fake()
const promise2 = promise1.then(() => new Promise((resolve, reject) => reject()))
promise2.then(null, fn)
setTimeout(() => {
assert(fn.called)
done()
}, 0);
})
it("2.2.7.1.2 fail的返回值是一个promise实例", (done) => {
const promise1 = new Promise((resolve, reject) => {
reject()
})
const fn = sinon.fake()
const promise2 = promise1.then(null, () => new Promise(resolve => resolve()))
promise2.then(fn)
setTimeout(() => {
assert(fn.called)
done()
}, 0);
})
it("2.2.7.1.2 fail的返回值是一个promise实例且失败", (done) => {
const promise1 = new Promise((resolve, reject) => {
reject()
})
const fn = sinon.fake()
const promise2 = promise1.then(null, () => new Promise((resolve, reject) => reject()))
promise2.then(null, fn)
setTimeout(() => {
assert(fn.called)
done()
}, 0);
})
it("2.2.7.2 如果success抛出一个异常e,promise2 必须被拒绝(rejected)并把e当作原因",
(done) => {
const promise1 = new Promise((resolve, reject) => {
resolve()
})
const fn = sinon.fake()
const error = new Error()
const promise2 = promise1.then(() => {
throw error
})
promise2.then(null, fn)
setTimeout(() => {
assert(fn.called)
assert(fn.calledWith(error))
done()
}, 0);
}
)
it("2.2.7.2 如果fail抛出一个异常e,promise2 必须被拒绝(rejected)并把e当作原因",
(done) => {
const promise1 = new Promise((resolve, reject) => {
reject()
})
const fn = sinon.fake()
const error = new Error()
const promise2 = promise1.then(null,() => {
throw error
})
promise2.then(null, fn)
setTimeout(() => {
assert(fn.called)
assert(fn.calledWith(error))
done()
}, 0);
}
)
});