同步编程通常来说易于调试和维护,然而,异步编程通常能获得更好的性能和更大的灵活性。异步的最大特点是无需等待。“Promises”渐渐成为JavaScript里最重要的一部分,大量的新API都开始promise原理实现。
Promise基本用法
new Promise()构造器可以用在传统的异步任务中,就像以前 setTimeout 和 XMLHttpRequest 的用法一样。一个新的 Promise 使用 new 关键字生成,同时,这个 Promises 提供了 resolve 和 reject 函数让我们执行回调操作:(写一个模板示例)
let p = new Promise(function(resolve, reject){
if('条件'){
resolve('成功')
}else{
reject('失败')
}
})
p.then(function(){})
.catch(function(){})
Promise.resolve() 和 Promise.reject() 可以直接被调用。
有时候,当判断出 promise 并不需要真正执行时,我们并不需要 使用 new 创建 Promise 对象,而是可以直接调用 Promise.resolve() 和 Promise.reject()。
因为 promise 肯定会返回,所以,我们可以使用 then 和 catch 方法处理返回值!
我们在写一个优化的示例
假设我们写个 函数请求:
function request(url, callback) {
setTimeout(() => {
callback({
code: 0,
data: "成功了",
});
}, 2000);
}
然后对其进行优化处理 此时用到了 async/await 。
async/await
async/await是写异步代码的新方式,它是generator的语法糖,以前的方法有回调函数和 Promise。async/await是基于Promise实现的,它不能用于普通的回调函数。
**async/await与Promise一样,是非阻塞的。async/await使得异步代码看起来像同步代码,**这正是它的魔力所在。
上图你可以看到
async function test2() {
const res = await request1(“/api/list”, 0); // 初始参数为0 两秒后加1 ,打印结果为1,2,3
console.log(res);
const res1 = await request1(“/api/list1”, res.code);
console.log(res1);
const res2 = await request1(“/api/list1”, res1.code);
console.log(res2);
}
function request(url, callback) {
setTimeout(() => {
callback({
code: 0,
data: "成功了",
});
}, 2000);
}
这两个其实一样,但是下者更为优化处理。
function request1(url, code) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
code: code + 1,
data: "成功了",
});
}, 2000);
});
}
项目中我们会尝尝用到 异步请求 async await 以及promise 。
当我点击了购车购物车按钮后在购物车页面。但是发现又问题看代码
原本别人写的(react项目)
//购物车数量调整
modifyQty = async (e, record, v) => {
const { dataSource } = this.props;
let packNum = v;
switch (e) {
case 'add':
packNum += 1;
break;
case 'minus':
if (packNum > 1) {
packNum -= 1;
break;
}
return;
case 'change':
if (record.packNum === v) return;
}
this.props.setState({shopLoading: true}, async () => {
const res = await modifyQty({
id: record?.id,
moq: record?.moq,
packNum,
unit: record?.unit
// packNum: record?.packNum
});
if (res.success) {
this.props.setState({
shopLoading: false,
dataSource: dataSource.map((item) => {
return {
...item,
cartList: item?.cartList.map((v) => {
if (record.id === v?.id) {
return {
...v,
packNum
};
}
return v;
})
};
})
});
} else {
this.props.setState({ shopLoading: false });
ElNotification({ type: 'error', message: res.msg || res.errorMsg });
}
}
);
后来我改动的
this.props.setState( { shopLoading: true }, async () => {
const res = await modifyQty({
id: record?.id,
moq: record?.moq,
packNum,
unit: record?.unit
});
if (res.success) {
this.props.setState(
{
shopLoading: false,
dataSource: dataSource.map((item) => {
return {
...item,
cartList: item?.cartList.map((v) => {
if (record.id === v?.id) {
return {
...v,
packNum
};
}
return v;
})
};
})
},
// 计算总和显示在购物车图标上
const total = this.props.dataSource.reduce((total, cur) => {
return (
total + cur.cartList.reduce((tempTotal, cur) => {
return tempTotal + cur.packNum;
}, 0)
);
}, 0);
//或者用forEach 写循环
// let total = 0;
// this.props.dataSource.forEach((cur) => {
// let tempTotal = 0;
// cur.cartList.forEach((cur) => {
// tempTotal = tempTotal + cur.packNum;
// });
// total = total + tempTotal;
// }, 0);
console.log(total);
}
);
} else {
this.props.setState({ shopLoading: false });
ElNotification({ type: 'error', message: res.msg || res.errorMsg });
}
}
);
之所以写了双循环是因为接口返回是两层,一般是一层就可以了。
但是发现代码还可以优化
写成 Promise的形式。
写一个方法
propsSetStateAsync(data) {
return new Promise((resolve) => {
this.props.setState(data, () => {
resolve(undefined);
});
});
}
//购物车数量调整
modifyQty = async (e, record, v) => {
const { dataSource } = this.props;
let packNum = v;
switch (e) {
case 'add':
packNum += 1;
break;
case 'minus':
if (packNum > 1) {
packNum -= 1;
break;
}
return;
case 'change':
if (record.packNum === v) return;
}
await this.propsSetStateAsync({ shopLoading: true });
const res = await modifyQty({
id: record?.id,
moq: record?.moq,
packNum,
unit: record?.unit
// packNum: record?.packNum
});
这里逻辑是每点击加减都要请求接口,应该是为了校验库存量,按照需求做吧,所以我是在请求接口后计算的。
if (res.success) {
await this.propsSetStateAsync({
shopLoading: false,
dataSource: dataSource.map((item) => {
return {
...item,
cartList: item?.cartList.map((v) => {
if (record.id === v?.id) {
return {
...v,
packNum
};
}
return v;
})
};
})
});
计算总和回赋值到购物车图表上
const total = this.props.dataSource.reduce((total, cur) => {
return (
total +
cur.cartList.reduce((tempTotal, cur) => {
return tempTotal + cur.packNum;
}, 0)
);
}, 0);
console.log(total); 拿到这个值,
// 计算拿到总数后,应该请求购物车接口改变数量
// 这里写购物车接口并刷新数据,但是目前还没有接口就空着了
} else {
this.props.setState({ shopLoading: false });
ElNotification({ type: 'error', message: res.msg || res.errorMsg });
}
};
使用过React的应该都知道,在React中,一个组件中要读取当前状态需要访问this.state,但是更新状态却需要使用this.setState,不是直接在this.state上修改。
setState(updater, callback)这个方法是用来告诉react组件数据有更新,有可能需要重新渲染。
生命周期中,setState是“异步”的 。
看到了一个不错的文章分享给你 了 看看这个介绍对我们有好处。