new Promise((resolve, reject) => {
setTimeout(() => {
reject(1)
}, 0)
}).then((value) => {
console.log('success', value) // 1
}, (error) => {
console.log('error', error) // 2
return error
}).then(value => {
console.log('success', value) // 3
return value
}).catch(error => {
console.log('catch error', error) // 4
}).then(value => {
console.log('success', value) // 5
return value
})
new Promise((resolve, reject) => {
setTimeout(() => {
reject(1)
}, 0)
}).then((value) => {
console.log('success', value) // 1
}).then(value => {
console.log('success', value) // 3
return value
}).catch(error => {
console.log('catch error', error) // 4
}).then(value => {
console.log('success', value) // 5
return value
})
try {
new Promise((resolve, reject) => {
setTimeout(() => {
reject(1)
}, 0)
}).then((value) => {
console.log('success', value)
})
} catch(error) {
console.log(error)
}
// 使用await可以捕获到
function test(id) {
return new MyPromise(((resolve, reject) => {
setTimeout(() => {
reject({ test: id })
}, 5000)
}))
}
async function main() {
try {
await test()
} catch(error) {
console.log('error', error)
}
}
main()
使用
const promise1 = Promise.resolve(123);
promise1.then((value) => {
console.log(value);
// expected output: 123
});
// 输出:123
不要在解析为自身的thenable 上调用Promise.resolve。这将导致无限递归
let thenable = {
then: (resolve, reject) => {
resolve(thenable)
}
}
Promise.resolve(thenable) //这会造成一个死循环
function resolved(result) {
console.log('Resolved');
}
function rejected(result) {
console.error(result);
}
Promise.reject(new Error('fail')).then(resolved, rejected);
// 输出: Error: fail
非Promise/Resolve Promise/Reject Promise,则 Promise.race 将解析为迭代中找到的第一个值。(也就是说如果存在非Promise值如一个数字2,将会返回数字2,因为数字2不需要等待结果) const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one');
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});
Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"
const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then((values) => {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
const PENDING = 'pending' // 等待态 Pending
const RESOLVED = 'resolved' // 执行态 Fulfilled
const REJECTED = 'rejected' // 拒绝态 Rejected
/**
* 基于 PromiseA+ 规范的 Promise 模型
* [【翻译】Promises/A+规范](https://www.ituring.com.cn/article/66566)
* @param {*} fn
*/
function MyPromise(fn) {
const that = this // 码可能会异步执行,用于获取正确的 this 对象
that.state = PENDING
that.value = null // 用于保存 resolve 或者 reject 中传入的值
that.resolvedCallbacks = [] // 用于保存 then 中的回调,因为当执行完 Promise 时状态可能还是等待中,这时候应该把 then 中的回调保存起来用于状态改变时使用
that.rejectedCallbacks = []
/**
* resolve函数
* @param {*} value
*/
function resolve(value) {
// 对于 resolve 函数来说,首先需要判断传入的值是否为 Promise 类型
if (value instanceof MyPromise) {
return value.then(resolve, reject)
}
// 使用setTimeout保证执行顺序
setTimeout(() => {
if (that.state === PENDING) {
console.log('resolve:', value, 'resolvedCallbacks len:', that.resolvedCallbacks.length)
that.state = RESOLVED
that.value = value
that.resolvedCallbacks.map(cb => cb(that.value))
}
}, 0)
}
/**
* reject函数
* @param {*} value
*/
function reject(value) {
setTimeout(() => {
if (that.state === PENDING) {
console.log('reject', value)
that.state = REJECTED
that.value = value
that.rejectedCallbacks.map(cb => cb(that.value))
}
}, 0)
}
/**
* 执行 Promise 中传入的函数
*/
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}
/**
* 兼容多种 Promise 的 resolutionProcedure 函数
* @param {*} promise2 - 新的promise
* @param {*} x - 终值
* @param {*} resolve
* @param {*} reject
* @returns
*/
function resolutionProcedure(promise2, x, resolve, reject) {
// 规范规定了 x 不能与 promise2 相等,这样会发生循环引用的问题
// 如果 promise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 promise
if (promise2 === x) {
return reject(new TypeError('Error'))
}
// 如果 x 为 Promise ,则使 promise 接受 x 的状态:
// 1. 如果 x 处于等待态,Promise 需保持为等待态直至 x 被执行或拒绝
// 2. 如果 x 处于执行态,用相同的值执行 promise
// 3. 如果 x 处于拒绝态,用相同的据因拒绝 promise
// 当然以上这些是规范需要我们判断的情况,实际上我们不判断状态也是可行的。
if (x instanceof MyPromise) {
console.log('isPromise')
x.then(function (value) {
resolutionProcedure(promise2, value, resolve, reject)
}, reject)
return
}
/**
* 接下来我们继续按照规范来实现"x 为对象或函数"的代码:
* - 首先创建一个变量 `called` 用于判断是否已经调用过函数
* - 然后判断 `x` 是否为对象或者函数,如果都不是的话,将 `x` 传入 `resolve` 中
* - 如果 `x` 是对象或者函数的话,先把 `x.then` 赋值给 `then`,然后判断 `then` 的类型,如果不是函数类型的话,就将 `x` 传入 `resolve` 中
* - 如果 `then` 是函数类型的话,就将 `x` 作为函数的作用域 `this` 调用之,并且传递两个回调函数作为参数,第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise`,两个回调函数都需要判断是否已经执行过函数,然后进行相应的逻辑
* - 以上代码在执行的过程中如果抛错了,将错误传入 `reject` 函数中
*/
let called = false
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then
if (typeof then === 'function') {
console.log('isThenable')
then.call(
x,
y => {
// resolvePromise
if (called) return
called = true
resolutionProcedure(promise2, y, resolve, reject)
},
e => {
// rejectPromise
if (called) return
called = true
reject(e)
}
)
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
/**
* Then方法
* 一个 promise 必须提供一个 then 方法以访问其当前值、终值和据因。
* onFulfilled 和 onRejected 必须被作为函数调用(即没有 this 值)
* then 方法可以被同一个 promise 调用多次,then 方法必须返回一个 promise 对象
* - 当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
* - 当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调
*
* 注意:不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve,只有出现异常时才会被 rejected。
* @param {*} onFulfilled 可选,如果 onFulfilled 不是函数,其必须被忽略
* @param {*} onRejected 可选,如果 onRejected 不是函数,其必须被忽略
* @returns
*/
MyPromise.prototype.then = function (onFulfilled, onRejected) {
const that = this
console.log('then', that.state)
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v
onRejected = typeof onRejected === 'function' ? onRejected : r => {
throw r
}
if (that.state === PENDING) {
// 每个 then 函数都需要返回一个新的 Promise 对象,该变量用于保存新的返回对象
return (promise2 = new MyPromise((resolve, reject) => {
that.resolvedCallbacks.push(() => {
try {
const x = onFulfilled(that.value) // onFulfilled第一个参数为 promise 的终值
resolutionProcedure(promise2, x, resolve, reject)
} catch (r) {
reject(r)
}
})
that.rejectedCallbacks.push(() => {
try {
const x = onRejected(that.value) // onRejected第一个参数为 promise 的据因
resolutionProcedure(promise2, x, resolve, reject)
} catch (r) {
reject(r)
}
})
}))
}
if (that.state === RESOLVED) {
// 这段代码和判断等待态的逻辑基本一致,无非是传入的函数的函数体需要异步执行,这也是规范规定的
return (promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
const x = onFulfilled(that.value)
resolutionProcedure(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
})
}))
}
if (that.state === REJECTED) {
return (promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
const x = onRejected(that.value)
resolutionProcedure(promise2, x, resolve, reject)
} catch (reason) {
reject(reason)
}
})
}))
}
}
function test(id) {
return new MyPromise(((resolve, reject) => {
setTimeout(() => {
resolve({ test: id })
}, 5000)
}))
}
try {
new MyPromise((resolve, reject) => {
setTimeout(() => {
// resolve(1)
reject(1)
}, 0)
}).then(value => {
console.log('success', value)
return value
}, error => {
console.log('error', error)
return 999
}).then(value => {
console.log('success2', value)
return test(value ? ++value : 99)
}).then(value => {
console.log('success3', value)
return value.test ? value.test + 1 : 0
}).then(value => {
console.log('success4', value)
})
} catch (error) {
console.log(error)
}
ES7 提出的async 函数,终于让 JS 对于异步操作有了终极解决方案
// promise写法
Promise.resolve(a)
.then(b => {
// do something
})
.then(c => {
// do something
})
// async/await写法
async () => {
const a = await Promise.resolve(a);
const b = await Promise.resolve(b);
const c = await Promise.resolve(c);
}
那么我们要如何实现一个 async/await 呢,首先我们要知道,async/await 实际上是对Generator(生成器)的封装,是一个语法糖。下面我们先来了解一些 Generator 函数。
ES6 新引入了 Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,通过next()方法可以切换到下一个状态,为改变执行流程提供了可能,从而为异步编程提供解决方案。
function* myGenerator() {
yield '1'
yield '2'
return '3'
}
const gen = myGenerator(); // 获取迭代器
gen.next() //{value: "1", done: false}
gen.next() //{value: "2", done: false}
gen.next() //{value: "3", done: true}
也可以通过给 next() 传参, 让 yield 具有返回值
function* myGenerator() {
console.log(yield '1') //test1
console.log(yield '2') //test2
console.log(yield '3') //test3
}
// 获取迭代器
const gen = myGenerator();
gen.next()
gen.next('test1')
gen.next('test2')
gen.next('test3')
我们看到Generator的用法,应该️会感到很熟悉,*/yield和async/await看起来其实已经很相似了,它们都提供了暂停执行的功能,但二者又有三点不同:
async/await自带执行器,不需要手动调用next()就能自动执行下一步async函数返回值是Promise对象,而Generator返回的是生成器对象await能够返回Promise的resolve/reject的值我们对async/await的实现,其实也就是对应以上三点封装Generator
这里async/await是关键字,不能重写,我们用函数来模拟:
function run(gen) {
//把返回值包装成promise
return new Promise((resolve, reject) => {
var g = gen()
function _next(val) {
//错误处理
try {
var res = g.next(val)
} catch(err) {
return reject(err);
}
if(res.done) {
return resolve(res.value);
}
//res.value包装为promise,以兼容yield后面跟基本类型的情况
Promise.resolve(res.value).then(
val => {
_next(val);
},
err => {
//抛出错误
g.throw(err)
});
}
_next();
});
}
测试一下,*相当于async, yield相当于await:
function* myGenerator() {
try {
console.log(yield Promise.resolve(1))
console.log(yield 2) //2
console.log(yield Promise.reject('error'))
} catch (error) {
console.log(error)
}
}
const result = run(myGenerator) //result是一个Promise
//输出 1 2 error
… 具体看这篇文章:9k字 | Promise/async/Generator实现原理解析
| [9k字 | Promise/async/Generator实现原理解析](https://juejin.cn/post/6844904096525189128#heading-13) |