完整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 = nullfail = nullresolve() {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 = succeedthis.fail = fail}}export default Promise2
test/index.ts
import * as chai from 'chai'const assert = chai.assertimport Promise from "../src/promise"describe('Promise', () => {it("Promise是一个类", () => {assert.isFunction(Promise)assert.isObject(Promise.prototype)})it("new Promise() 如果接受不是一个函数就报错", () => {assert.throw(() => {//@ts-ignorenew Promise()})assert.throw(() => {//@ts-ignorenew Promise(1)})assert.throw(() => {//@ts-ignorenew Promise(false)})})it('new Promise(fn) 会生成一个对象,对象有then方法', () => {const promise = new Promise(() => { })assert.isFunction(promise.then)})it('new Promise(fn)中的fn立即执行', () => {let called = falseconst promise = new Promise(() => {called = true})//@ts-ignoreassert(called === true)})it('new Promise(fn)中的fn执行的时候接受reject和resolve两个函数', () => {let called = falseconst promise = new Promise((resolve,reject) => {called = trueassert.isFunction(resolve)assert.isFunction(reject)})//@ts-ignoreassert(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-ignorepromise.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-ignorepromise.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.assertimport Promise from "../src/promise"describe('Promise', () => {it("Promise是一个类", () => {assert.isFunction(Promise)assert.isObject(Promise.prototype)})it("new Promise() 如果接受不是一个函数就报错", () => {assert.throw(() => {//@ts-ignorenew Promise()})assert.throw(() => {//@ts-ignorenew Promise(1)})assert.throw(() => {//@ts-ignorenew 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-ignorepromise.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-ignorepromise.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.1resolveWith(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.4x.then((result) => {this.resolve(result)}, (reason) => {this.reject(reason)})}//2.3.3另外,如果x是个对象或者方法if (x instanceof Object) {let thentry {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.assertimport Promise from "../src/promise"describe('Promise', () => {it("Promise是一个类", () => {assert.isFunction(Promise)assert.isObject(Promise.prototype)})it("new Promise() 如果接受不是一个函数就报错", () => {assert.throw(() => {//@ts-ignorenew Promise()})assert.throw(() => {//@ts-ignorenew Promise(1)})assert.throw(() => {//@ts-ignorenew 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-ignorepromise.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-ignorepromise.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 xtry {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 xtry {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.1resolveWith(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.4x.then((result) => {this.resolve(result)}, (reason) => {this.reject(reason)})}//2.3.3另外,如果x是个对象或者方法if (x instanceof Object) {let thentry {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 xtry {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 xtry {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.1resolveWith(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.4x.then((result) => {this.resolve(result)}, (reason) => {this.reject(reason)})}//2.3.3另外,如果x是个对象或者方法if (x instanceof Object) {let thentry {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 Promise2function nextTick(fn) {if (process !== undefined && typeof process.nextTick === 'function') {return process.nextTick(fn)}var counter = 1var observer = new MutationObserver(fn)var textNode = document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})counter = (counter + 1) % 2textNode.data = String(counter)}
最终版本
优化代码
/src/promise.ts
class Promise2 {state = "pending"callBacks = []private resolveOrReject(state, data, i) {if (this.state !== 'pending') return;this.state = statenextTick(() => {this.callBacks.forEach((handle) => {if (typeof handle[i] === 'function') {let xtry {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 thentry {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 Promise2function nextTick(fn) {if (process !== undefined && typeof process.nextTick === 'function') {return process.nextTick(fn)}var counter = 1var observer = new MutationObserver(fn)var textNode = document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})counter = (counter + 1) % 2textNode.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.assertimport Promise from "../src/promise"describe('Promise', () => {it("Promise是一个类", () => {assert.isFunction(Promise)assert.isObject(Promise.prototype)})it("new Promise() 如果接受不是一个函数就报错", () => {assert.throw(() => {//@ts-ignorenew Promise()})assert.throw(() => {//@ts-ignorenew Promise(1)})assert.throw(() => {//@ts-ignorenew 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-ignorepromise.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-ignorepromise.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);})});

