v1
仅能处理异步的成功和失败
实现
// no-log
// 自定义函数`Promi`来模拟`Promise`
function ProMi(executor) {
let that = this
that.status = 'pending'
that.failCallBack = undefined
that.successCallback = undefined
executor(resolve.bind(that), reject.bind(that))
function resolve(params) {
if (that.status === 'pending') {
that.status = 'success'
if (that.successCallback) {
that.successCallback(params)
} else {
console.error('未传入成功回调')
}
}
}
function reject(params) {
if (that.status === 'pending') {
that.status = 'fail'
if (that.failCallBack) {
that.failCallBack(params)
} else {
console.error('未传入失败回调')
}
}
}
}
ProMi.prototype.then = function (successCallback, failCallBack) {
this.successCallback = successCallback
this.failCallBack = failCallBack
}
测试一下Promi
new ProMi(function (resolve, reject) {
setTimeout(() => {
resolve('{"msg": "Hello world!"}')
}, 1000)
}).then((data) => {
// log-async
console.log(data)
}, null)
// 由于 try catch只能捕捉同步方法的错误,这里假装有错误
new ProMi(function (resolve, reject) {
setTimeout(() => {
reject('{"msg": "我是一个一个错误"}')
}, 1000)
}).then(null, (err) => {
// log-async
console.log(err)
})
这便是,Promise
的最基本原理。
bug
但是当我们使用如下同步代码
测试时,发现并不凑效(报错:未传入成功/失败回调,需要查看控制台)
new ProMi(function (resolve, reject) {
// 这是一段同步代码
let sum = 0
for (let i = 0; i < 10000; i++) {
sum = sum + i
}
resolve(sum)
}).then((data) => {
// 不走这,因为没有传入成功的回调函数
// log-async
console.log(data)
})
new ProMi(function (resolve, reject) {
// 这是一段同步代码
try {
abc.alert(1)
} catch (e) {
reject(e.message)
}
}).then(null, (err) => {
// 不走这,因为没有失败的回调函数
// log-async
console.log(err)
})
v2
能处理异步+同步的成功和失败
实现
对于同步方法,failCallBack
不能及时传入,此时只需要修改下 resolve 和 reject
function ProMise(executor) {
let that = this
that.status = 'pending'
that.failCallBack = undefined
that.successCallback = undefined
that.error = undefined
executor(resolve.bind(that), reject.bind(that))
function resolve(params) {
if (that.status === 'pending') {
that.status = 'success'
if (that.successCallback) {
that.successCallback(params)
} else {
// log-async
console.log('未第一时间传入成功回调,若干毫秒后将重试')
setTimeout(() => {
that.successCallback(params)
}, 1)
}
}
}
function reject(params) {
if (that.status === 'pending') {
that.status = 'fail'
if (that.failCallBack) {
that.failCallBack(params)
} else {
// log-async
console.log('未第一时间传入失败回调,若干毫秒后将重试')
setTimeout(() => {
that.failCallBack(params)
}, 1)
}
}
}
}
ProMise.prototype.then = function (full, fail) {
this.successCallback = full
this.failCallBack = fail
}
window.ProMise = ProMise
// 再测试一遍同步回调
new ProMise(function (resolve, reject) {
try {
abc.alert(1)
} catch (e) {
reject(e.message)
}
}).then(null, (err) => {
// log-async
console.log(err)
})
new ProMise(function (resolve, reject) {
let start = new Date().getTime()
let sum = 0
for (let i = 0; i < 3000 * 3000; i++) {
sum = sum + i
}
let end = new Date().getTime()
// log-async
console.log(end - start)
resolve(sum)
}).then(data => {
// log-async
console.log(data)
})