Promise简单使用
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
### })
Promsie基本术语和要求
术语
- "promise"是具有then方法的对象或函数,其行为符合此规范
- "thenable"是定义then方法的对象或函数,可以是个对象也可以是个函数
- "value"是任意合法的Javascript值,(包括undefined,thenable, promise)
- "exception"是使用throw语句抛出的值
- "reason"是表示promise为什么被rejected的值
要求
1.Promsie状态
- 一个promise必须处于三种状态之一: 请求态(pending), 完成态(fulfilled),拒绝态(rejected)
- 当promise处于请求状态(pending)时,promise可以转为fulfilled或rejected状态
- 当promise处于完成状态(fulfilled)时,promise不能转为任何其他状态,必须有一个值,且此值不能改变
- 当promise处于拒绝状态(rejected)时,promise不能转为任何其他状态,必须有一个原因(reason),且此原因不能改变
2.then方法
promise必须提供then方法来存取它当前或最终的值或者原因。 promise的then方法接收两个参数
promise.then(onFulfilled, onRejected)
2.1 onFulfilled和onRejected都是可选的参数:
如果 onFulfilled不是函数,必须忽略,如果 onRejected不是函数,必须忽略
2.2 如果onFulfilled是函数:
- 此函数必须在promise 完成(fulfilled)后被调用,并把promise 的值作为它的第一个参数
- 此函数在promise完成(fulfilled)之前绝对不能被调用
- 此函数绝对不能被调用超过一次
2.3 如果onRejected是函数
......
2.4 在执行上下文堆栈(execution context)仅包含平台代码之前,不得调用 onFulfilled和onRejected(暂时忽略)
2.5 onFulfilled和onRejected必须被当做函数调用
英文原版:(onFulfilled and onRejected must be called as functions (i.e. with no this value))
2.6 then可以在同一个promise里被多次调用
- 如果/当 promise 完成执行(fulfilled),各个相应的onFulfilled回调 必须根据最原始的then 顺序来调用
- 如果/当 promise 被拒绝(rejected),各个相应的onRejected回调 必须根据最原始的then 顺序来调用
初步的源码:
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if(this.status === PENDING) {
this.status = FULFILLED
this.value = value
}
}
const reject = (reason) => {
if(this.status === PENDING) {
this.status = REJECTED
this.reason = reason
}
}
executor(resolve, reject)
}
then (onFulfilled, onRejected) {
if(this.status === FULFILLED) {
onFulfilled(this.value)
}
if(this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = MyPromise
稍作改善
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
const resolve = (value) => {
if(this.status === PENDING) {
this.status = FULFILLED
this.value = value
}
}
const reject = (reason) => {
if(this.status === PENDING) {
this.status = REJECTED
this.reason = reason
}
}
try { // 改动点
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
then (onFulfilled, onRejected) {
if(this.status === FULFILLED) {
onFulfilled(this.value)
}
if(this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = MyPromise
实现真正的异步操作 问题:
let promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('Success')
}, 2000)
})
promise.then((value) => {
console.log('FulFilled', value)
}, (reason) => {
console.log('Rejected', reason)
})
解决方法:采用发布订阅模式
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if(this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 发布
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if(this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 发布
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
then (onFulfilled, onRejected) {
if(this.status === FULFILLED) {
onFulfilled(this.value)
}
if(this.status === REJECTED) {
onRejected(this.reason)
}
if(this.status === PENDING) {
// 订阅
this.onFulfilledCallbacks.push(() => {
onFulfilled(this.value)
})
// 订阅
this.onRejectedCallbacks.push(() => {
oRejected(this.reason)
})
}
}
}
Promise链式调用特性
特性1:通过return返回结果,下一个then的回调函数里能获取到
let promise1 = new Promise((resolve, reject) => {
resolve('success')
}).then((value) => {
return value
}).then((value) => {
console.log('value', value)
})
特性2:return的如果是一个promise的话,下一个then获取到的是这个promsie返回的结果,不是这个promise
let promise1 = new Promise((resolve, reject) => {
resolve('success')
}).then((value) => {
return new Promise((resolve) => {
resolve('success2')
})
}).then((value) => {
console.log('value', value)
})
特性3:上一个then返回的promise执行reject,下一个then走的是onRejected
let promise1 = new Promise((resolve, reject) => {
reject('reason')
}).then((value) => {
console.log('value', value)
}, (reason) => {
console.log('reason', reason)
})
特性4:上一个then走了失败的回调函数以后,下一个then走成功回调函数,值是上一个rejected返回的值
let promise1 = new Promise((resolve, reject) => {
reject('reason')
}).then((value) => {
console.log('value', value)
}, (reason) => {
console.log('reason', reason)
}).then((value) => {
console.log('value2', value)
})
特性5:上一个then的回调发生异常,下一then走的是失败的回调函数
let promise1 = new Promise((resolve, reject) => {
reject('reason')
}).then((value) => {
throw new Error('Error')
}, (reason) => {
throw new Error('Error')
}).then((value) => {
console.log('Error', value)
}, (reason) => {
console.log('reason2', reason)
})
特性6:上一个then回调发生异常,下一个then没有定义onRejected,但是后面跟一个.catch,会执行.catch的回调
let promise1 = new Promise((resolve, reject) => {
reject('reason')
}).then((value) => {
throw new Error('Error')
}, (reason) => {
throw new Error('Error')
}).then((value) => {
console.log('Error', value)
}).catch((r) => {
console.log('r', r)
})
特性7:又有then,又有catch,会找最近的失败的回调函数执行
let promise1 = new Promise((resolve, reject) => {
reject('reason')
}).then((value) => {
throw new Error('Error')
}, (reason) => {
throw new Error('Error')
}).then((value) => {
console.log('Error', value)
}, (r) => {
console.log('onRejected中的r', r)
}).catch((r) => {
console.log('catch中的r', r)
})
特性8:catch以后继续.then执行成功的回调函数
let promise1 = new Promise((resolve, reject) => {
reject('reason')
}).then((value) => {
throw new Error('Error')
}, (reason) => {
throw new Error('Error')
}).then((value) => {
console.log('Error', value)
}, (r) => {
console.log('onRejected中的r', r)
}).catch((r) => {
console.log('catch中的r', r)
}).then((value) => {
console.log('catch之后的then的onFulFilled',value)
}, (reason) => {
console.log('catch之后的then的onRejected',reason)
})
总结
执行成功的的回调函数的条件
- 上一个then return了一个普通的javascript值
- 上一个then return新的promise,并且这个promise最后状态是成功,resolve(value),这个value在回调函数里可以拿到
执行失败的回调函数的条件
- 上一个then return新的promise,并且这个新的promise最后状态是失败,reject(reason),reason在回调函数里可以获取到
- 上一个then抛出了异常
then为什么最后能进行链式调用,因为它返回了一个新的promise
链式调用源码
then必须返回一个promise
then (onFulfilled, onRejected) {
let promise2 = new MyPromise((resolve, reject) => {
if(this.status === FULFILLED) {
try { // 失败总结2
let x = onFulfilled(this.value)
resolve(x)
} catch (e) {
reject(e)
}
}
if(this.status === REJECTED) {
try {
let x = onRejected(this.reason)
reject(x)
} catch (e) {
reject(e)
}
}
if(this.status === PENDING) {
// 订阅
this.onFulfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.value)
resolve(x)
} catch (e) {
reject(e)
}
})
// 订阅
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.reason)
reject(x)
} catch (e) {
reject(e)
}
})
}
})
return promise2
}
- 如果onFulfilled或onRejected返回一个值x, 运行 Promise Resolution
- 如果onFulfilled或onRejected抛出一个异常e,promise2 必须被拒绝(rejected)并把e当作原因
- 如果onFulfilled不是一个方法,并且promise1已经完成(fulfilled), promise2必须使用与promise1相同的值来完成(fulfiled)
- 如果onRejected不是一个方法,并且promise1已经被拒绝(rejected), promise2必须使用与promise1相同的原因来拒绝(rejected)
链式调用重写then方法
x不一定是普通值,可能又是一个promise
let promise1 = new MyPromise((resolve, reject) => {
resolve('success')
}).then((value) => {
return new MyPromise((resolve, reject) => {
resolve('success2')
})
}).then((value) => {
console.log('value', value)
})
对x的值进行判断
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if(this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 发布
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if(this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 发布
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
then (onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
if(this.status === FULFILLED) {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
resolve(x)
} catch (e) {
reject(e)
}
}
if(this.status === REJECTED) {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}
if(this.status === PENDING) {
// 订阅
this.onFulfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
// 订阅
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
resolve(x)
}
PromiseA+规范:如果回调函数返回了一个promise,那么现在当前promise的状态取决于返回的promsie的状态
所以禁止返回的promsie和当前promsie不能是同一个
这里有两个问题:
-
onFulfilled必须是异步操作完成后再调用
-
这个时候promise2这个实例还没创建完成
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 发布
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 发布
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
resolve(x)
} catch (e) {
reject(e)
}
})
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === PENDING) {
// 订阅
this.onFulfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
resolve(x)
} catch (e) {
reject(e)
}
})
// 订阅
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
resolve(x)
}
实现resolvePromise
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
constructor(executor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 发布
this.onFulfilledCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 发布
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
console.log('onRejected低啊用')
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === PENDING) {
// 订阅
this.onFulfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
// 订阅
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
return promise2
}
}
function resolvePromise(promise2, x, resolve, reject) {
if(promise2 === x) {
console.log(1)
return reject(new TypeError('Chaining cycle detected for promise#<MyPromise>'))
}
if((typeof x === 'object' && x !== null) || typeof x === 'function') {
try {
let then = x.then // throw error
if(typeof then === 'function') { // 走到这里就认定x是一个Promise
then.call(x, (y) => {
resolve(y)
}, (r) => {
reject(r)
})
} else {
resolve(x)
}
} catch(e) {
reject(e)
}
} else {
resolve(x)
}
}
- 返回的是个promsie而且调用了多次resolve或reject
- x的回调函数又是一个promise
- promise2.then().then().then().then
function resolvePromise(promise2, x, resolve, reject) {
if(promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise#<MyPromise>'))
}
let called = false
if((typeof x === 'object' && x !== null) || typeof x === 'function') {
try {
let then = x.then // throw error
if(typeof then === 'function') { // 走到这里就认定x是一个Promise
then.call(x, (y) => {
if(called) return
called = true
resolvePromise(promise2, y, resolve, reject)
}, (r) => {
if(called) return
called = true
reject(r)
})
} else {
resolve(x)
}
} catch(e) {
if(called) return
called = true
console.log('hahahha')
reject(e)
}
} else {
resolve(x)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === PENDING) {
// 订阅
this.onFulfilledCallbacks.push(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
// 订阅
this.onRejectedCallbacks.push(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
return promise2
}