异步编程
状态
- 状态值
- pending 连接状态
- fulfilled 成功状态
- reject 拒绝状态
- 状态是不可逆的,状态谁先改变则是谁
- 有两个回调函数
resolve
成功reject
失败
then
- 包含两个回调函数,一个成功回调,一个失败回调
js
new Promise((resolve, reject) => {
resolve('成功')
}).then(result => {
console.log(result)
})
new Promise((resolve, reject) => {
reject('失败')
}).then(null, reason => {
console.log(reason)
})
链式调用,优先执行先定义的
then
方法jsnew Promise((resolve, reject) => { resolve('成功') }).then(res => { console.log(res) }).then(res => { console.log(res) }) // 成功, undefined
每个
then
方法返回的也是一个promise
jslet p1 = new Promise((resolve, reject) => { resolve('成功') }) let p2 = p1.then(value => { console.log(value) }, reason => { console.log(reason) }) setTimeout(() => { console.log(p1) console.log(p2) }) // ’成功', p1, p2
多个
then
方法时,下一个then
方法是对上一个then
返回(return)的值进行处理,且默认状态是resolve
成功jsnew Promise((resolve, reject) => { reject("失败"); }).then( result => console.log(result), reason => console.log(reason) ).then( result => console.log("成功"), reason => console.log("失败") ) // 失败, 成功 new Promise((resolve, reject) => { resolve("成功"); }).then( result => { return new Promise((resolve, reject) => { reject('第二个错误promise') }) }, reason => console.log(reason) ).then( result => console.log("成功"), reason => console.log('error ' + reason) ) // error 第二个错误promise
其它类型的
promise
封装jsnew Promise((resolve, reject) => { resolve("成功"); }).then( result => { class Fn { then(resolve, reject){ resolve('这是对象') } } return new Fn() } ).then( result => console.log(result), reason => console.log('error ' + reason) ) // 这是对象
catch
- 可以捕获
promise
抛出的错误 - 建议统一将方法放在最后执行捕获
- 前面
then
方法做了错误回调处理,则不执行catch
方法
js
new Promise((resolve, reject) => {
reject("失败");
}).then(
result => console.log(result),
reason => console.log('error ' + reason)
).catch(err => {
console.log(err);
})
// error 失败
finally
无论状态是resolve
或 reject
都会执行此动作,finally
与状态无关。
js
new Promise((resolve, reject) => {
resolve("成功");
}).then(
result => console.log(result)
).catch(err => {
console.log(err);
}).finally(() => {
console.log("resolve/reject状态都会执行")
})
// 成功, resolve/reject状态都会执行
使用promise异步加载图片
js
function loadImage(src, id) {
return new Promise((resolve, reject) => {
const image = new Image()
image.src = src
image.onload = () => {
resolve(image)
}
image.onerror = reject
document.querySelector(id).appendChild(image)
})
}
定时器封装
js
function timeout(delay = 1000) {
return new Promise(resolve => setTimeout(resolve, delay))
}
timeout(2000).then(() => {
console.log('2秒后输出')
return timeout(1000)
}).then(() => {
console.log('再过1秒后输出')
})
其他接口方法
resolve
使用 promise.resolve
方法可以快速的返回一个 promise
对象
js
Promise.resolve("Mondo").then(value => {
console.log(value); // Mondo
});
缓存查询数据
js
function query(name) {
const cache = query.cache || (query.cache = new Map());
if (cache.has(name)) {
console.log("缓存");
return Promise.resolve(cache.get(name));
}
return ajax(`http://test.com?name=${name}`).then(
res => {
cache.set(name, response);
console.log("没走缓存");
return res;
}
);
}
query("Mondo").then(res => {
console.log(res);
});
reject
和 Promise.resolve
类似,reject
生成一个失败的promise
js
new Promise((resolve, reject) => {
resolve('成功')
}).then(value => {
if (value !== 'mondo') {
return Promise.reject('参数错误')
}
}).catch(error => {
console.log(error) // 参数错误
})
all
使用Promise.all
方法可以同时执行多个并行异步操作
- 任何一个
Promise
执行失败就会调用catch
方法 - 适用于一次发送多个异步操作
- 参数必须是可迭代类型,如Array/Set
- 成功后返回
promise
结果的有序数组
js
const p1 = new Promise((resolve, reject) => {
resolve("第一个Promise");
});
const p2 = new Promise((resolve, reject) => {
resolve("第二个Promise");
});
Promise.all([p1, p2]).then(res => {
console.log(res); // ['第一个Promise', '第二个Promise']
}).catch(error => {
console.log(error);
});
allSettled
Promise.allSettled
用于处理多个promise
,只关注执行完成,不关注是否全部执行成功,allSettled
状态只会是fulfilled
。
js
const p1 = new Promise((resolve, reject) => {
resolve("第一个Promise");
});
const p2 = new Promise((resolve, reject) => {
reject("第二个Promise");
});
Promise.allSettled([p1, p2]).then(res => {
console.log(res);
})
打印出的来值为
race
Promise.race
批量处理多个 Promise
,谁先返回状态就执行哪个
- 以最先返回的
promise
为准 - 如果最先返加的状态为
rejected
那么整个promise
为rejected
执行catch - 如果参数不是promise,内部将自动转为promise
js
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第一个Promise");
}, 1000)
});
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject("第二个Promise");
})
});
Promise.race([p1, p2]).then(res => {
console.log(res);
}).catch(error => {
console.log(error) // 第二个Promise
})
任务队列
如果 then
返回一个 promise
时,后面的 then
就是对返回的 promise
进行处理,只有当前一个 promise
状态 resolve
后,下一个 then
方法才会执行
js
let promise = Promise.resolve();
let p1 = promise.then(() => {
return new Promise(resolve => {
setTimeout(() => {
console.log(`p1`);
resolve();
}, 2000);
});
});
p1.then(() => {
return new Promise((a, b) => {
setTimeout(() => {
console.log(`p2`);
}, 1000);
});
})
// p1, p2
实现一个队列输出
js
// 使用map
function queue(num) {
let promise = Promise.resolve()
num.map(v => {
promise = promise.then(_ => {
return new Promise(resolve => {
setTimeout(() => {
console.log(v)
resolve()
}, 1000)
})
})
})
}
// 使用reduce
function queue(num) {
let promise = Promise.resolve()
num.reduce((promise, v) => {
return promise.then(_ => {
return new Promise(resolve => {
setTimeout(() => {
console.log(v)
resolve();
}, 1000)
})
})
}, Promise.resolve())
}
queue([1, 2, 3, 4, 5, 6])
async与await语法糖
async
在函数前加上 async
,函数将返回一个 promise
,可以像使用 promise
一样使用
- 无论函数有没有返回值,
promise
状态都是resolve
完成状态
js
async function fn() {
return 'mondo'
}
console.log(fn())
fn().then(res => {
console.log(re)
})
await
使用 await
会等待 promise
执行完
await
后面一般是promise,如果不是直接返回await
必须放在 async 定义的函数中使用await
用于替代then
使编码更优雅
js
async function fn() {
let promise = new Promise(resolve => {
setTimeout(() => {
resolve('mondo')
}, 1000)
})
let a = await promise
console.log(a)
}
fn()
async 延时函数
js
async function sleep(delay = 2000) {
return new Promise(resolve => {
setTimeout(() => {
resolve()
}, delay)
})
}
async function show(arr) {
for (const v of arr) {
await sleep()
console.log(v)
}
}
show([1, 2])
class 与 await 的结合
js
class User {
constructor(name) {
this.name = name
}
// 定义then方法,返回 resolve 状态
then(resolve, reject) {
setTimeout(() => {
resolve(this.name)
}, 1000)
}
}
async function get() {
let user = await new User('mondo')
console.log(user)
}
get() // mondo
async 错误处理
使用
catch
捕获错误jsasync function fn() { throw new Error('error') } fn().catch(err => { console.log(err) })
使用
try...catch
捕获错误jsasync function fn() { try { const a = await fn1() const b = await fn2() return b } catch (error => { console.log(error) }) } fn()
await 并行执行
js
async function p1() {
return 'mondo'
}
async function p2() {
return 'imondo.cn'
}
async function fn() {
const h1 = p1()
const h2 = p2()
console.log(h1, h2)
const v1 = await h1
const v2 = await h2
console.log(v1, v2)
}
fn() // 同时打印 mondo imondo.cn
// 或者
async function fn1() {
const res = await Promise.all([p1(), p2()])
console.log(res)
}
fn1() // 同时打印 ['mondo', 'imondo.cn']
宏任务与微任务执行顺序
同步任务优先执行
微任务优先宏任务执行
微任务
promise
宏任务
setTimeout
js
setTimeout(() => {
console.log(1)
}, 0)
new Promise(reslove => {
reslove()
console.log(2)
}).then(() => {
console.log(3')
})
console.log(4) // 2,4,3,1
手写一个Promise
- 实现promise基本用法
- 实现then链式调用方法
- 实现all方法
- 实现race方法
js
class MoPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECT = "reject";
constructor(executor) {
this.status = MoPromise.PENDING;
this.value = null;
this.callbacks = [];
// 出现异常时执行reject方法
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
resolve(value) {
// 只有pending状态下才执行,且状态变了后不可修改
if (this.status === MoPromise.PENDING) {
this.status = MoPromise.FULFILLED;
this.value = value;
setTimeout(() => {
this.callbacks.map(callback => {
callback.onFulfilled(value);
});
});
}
}
reject(reason) {
if (this.status === MoPromise.PENDING) {
this.status = MoPromise.REJECT;
this.value = reason;
setTimeout(() => {
this.callbacks.map(callback => {
callback.onReject(reason);
});
});
}
}
then(onFulfilled, onReject) {
// 当回调函数没传时,定义默认函数
if (typeof onFulfilled !== "function") {
onFulfilled = () => this.value; // then穿透传值
}
if (typeof onReject !== "function") {
onReject = () => this.value;
}
// 返回promise,实现链式操作
let promise = new MoPromise((resolve, reject) => {
// 准备状态处理,以后需要执行的任务队列
if (this.status === MoPromise.PENDING) {
this.callbacks.push({
onFulfilled: value => {
this.parse(promise, onFulfilled(value), resolve, reject);
},
onReject: value => {
this.parse(promise, onReject(value), resolve, reject);
}
});
}
// 只有状态改变 才执行方法
if (this.status === MoPromise.FULFILLED) {
// 放置在任务队列,实现异步操作
setTimeout(() => {
this.parse(promise, onFulfilled(this.value), resolve, reject);
});
}
if (this.status === MoPromise.REJECT) {
setTimeout(() => {
this.parse(promise, onReject(this.value), resolve, reject);
});
}
});
return promise;
}
parse(promise, result, resolve, reject) {
if (promise === result) {
throw new TypeError("不可返回相同类型");
}
try {
// 如果then返回promise
if (result instanceof MoPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
}
static resolve(value) {
return new MoPromise((resolve, reject) => {
if (value instanceof MoPromise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(value) {
return new MoPromise((resolve, reject) => {
if (value instanceof MoPromise) {
value.then(resolve, reject);
} else {
reject(value);
}
});
}
static all(promises) {
const values = [];
return new MoPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(
value => {
values.push(value);
if (values.length === promises.length) {
resolve(values);
}
},
reason => {
reject(reason);
}
);
});
});
}
static race(promises) {
return new MoPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(
value => {
resolve(value);
},
reason => {
reject(reason);
}
);
});
});
}
}