Promise[ES6新增一个对象]
语法
resolve 函数:处理异步任务成功的结果 -> resolve('成功')
reject 函数:处理异步任务失败的结果 -> resolve('失败')
let promise = new Promise(function(resolve,reject)){
//resolve 函数
//reject 函数
//异步任务封装
setTimeout(function(){
if(true){
resolve('成功')
}else{
reject('成功')
}
},1000)
})
promise.then(function(result){ //与回调函数不同 结果用then来返回
result=>成功
})
promise.catch(function(error){
error=>失败
})
作用
同回调函数一样对异步任务进行封装,但能更好的更优雅的处理异步任务结果
使用
let promise = new Promise(function(resolve,reject)){
//resolve 函数
//reject 函数
//异步任务封装
setTimeout(function(){
if(true){
resolve('成功')
}else{
reject('成功')
}
},1000)
})
promise.then(function(result){
result=>成功
})
promise.catch(function(error){
error=>失败
})
promise AJAX封装
function myPromise(options) {
return new Promise((resolve, reject) => {
ajax({
method: options.method,
url: options.url,
data: options.data,
success: function (result) {
resolve(result)
},
fail:function(error){
reject(error)
}
})
})
}
promise链式调用
比 回调函数 更好的更优雅的方法处理异步结果
有多个请求,后面请求需要用到前面请求的结果,若使用回调函数,会出现回调嵌套(回调地狱问题)
请求:A -> B(a) -> C(b)
参数: a b
// 链式写法 简化改良版
promiseA.then(a=>{
let promiseB = new Promise((resolve,reject)=>{
//封装B异步操作 a
})
return promiseB
}).then(b=>{ //用then处理结果
let promiseC = new Promise((resolve,reject)=>{
//封装C异步操作 b
})
return promiseC
}).then(c=>{
console.log(c)
})
//未简化版
let promiseA = new Promise((resolve,reject)=>{
//封装A异步操作
})
let promiseC = new Promise((resolve,reject)=>{
//封装C异步操作
})
promiseA.then(a=>{
成功结果
let promiseB = new Promise((resolve,reject)=>{
//封装B异步操作 a
})
promiseB.then(b=>{
let promiseC = new Promise((resolve,reject)=>{
//封装C异步操作 b
})
promiseC.then(c=>{
})
})
})
链式调用事例
<script src="./myajax.js"></script>
<script>
/*
封装一个函数获取promsie对象, promise对象封装处理网络请求异步任务
options = {
method:'get',
url:''
data:{}
}
*/
myPromise({
method: 'get',
url: 'http://10.7.162.150:8089/api/shop/list',
}).then(result => {
let list = result.resultInfo.list //商品列表
return myPromise({
method: 'get',
url: 'http://10.7.162.150:8089/api/shop/find',
data: {
id: list[0].id, //商品详情
},
})
}).then(resultB => {
console.log(resultB)
})
</script>
如何使用promise
写项目
调用接口获取后端数据
1. 原生ajax
let xhr = new XMLHttpRequest()
xhr.open()
xhr.send()
xhr.onreadystatechange=function(){
}
2. 封装ajax回调函数
引入myajax.js
ajax({
method:'get',
url:'',
data:{},
success:function(res){},
fail:function(error){}
})
3. 封装promise写法
引入myajax.js
myPromise({
method:'get',
url:'',
data:{}
}).then(res=>{
成功
}).catch(error=>{
失败
})
-->
product
商品列表:
<div class="container">
<!-- 动态渲染 -->
</div>
<script src="./js/myajax.js"></script>
<script>
/**
* 获取商品列表数据
*/
function getProductList() {
// ajax({
// method: 'get',
// url: 'http://10.7.162.150:8089/api/shop/list',
// success: function (res) {
// showProductList(res.resultInfo.list)
// },
// })
myPromise({
method:'get',
url:'http://10.7.162.150:8089/api/shop/list',
}).then(res=>{
showProductList(res.resultInfo.list)
})
}
/**
* 动态渲染商品列表
*/
function showProductList(productList) {
let list = productList.map(item => {
return `<div class="product-item" onclick="onDetail(${item.id})">
<img src="${item.picture}" alt="pic1">
<p>${item.product}</p>
<p>¥${item.price} ${item.putaway}人已买</p>
</div>`
})
const rootEle = document.querySelector('.container')
rootEle.innerHTML = list.join('')
}
/**
* 跳转详情页
* @param {*} id
*/
function onDetail(id) {
// 跳转详情页
location.href = './detail.html?id=' + id
}
getProductList()
</script>
商品详情 放大镜:
<a href="./index.html">返回首页</a>
<div class="glass-wrapper">
<!-- 动态渲染 -->
</div>
<script src="./js/myajax.js"></script>
<script src="./js/glass.js"></script>
<script>
/**
* 获取商品id
* @returns
*/
function getProductId() {
let str = location.search // ?id=2
let id = str.split('=')[1]
return id
}
/**
* 获取商品详情
*/
function getProductDetail() {
let id = getProductId()
// ajax({
// method: 'get',
// url: 'http://10.7.162.150:8089/api/shop/find',
// data: {
// id,
// },
// success: function (res) {
// showProductDetail(res.resultInfo)
// },
// })
myPromise({
method:'get',
url:'http://10.7.162.150:8089/api/shop/find',
data:{id}
}).then(res=>{
console.log(res)
showProductDetail(res.resultInfo)
})
}
/**
* 动态渲染详情
*/
function showProductDetail(product) {
let str = `<div class="container" id="glass1">
<div class="left-wraper">
<div class="m-left">
<img src="${product.picture}" alt="show1" />
<!-- 遮罩层 -->
<div class="mask"></div>
</div>
<ul>
<li class="active"><img src="${product.list[0]}" alt="small1" /></li>
<li><img src="${product.list[1]}" alt="small2" /></li>
<li><img src="${product.list[2]}" alt="small3" /></li>
<li><img src="${product.list[3]}" alt="small4" /></li>
</ul>
</div>
<!-- 放大镜 -->
<div class="right-wraper">
<img src="${product.picture}" alt="big1" />
</div>
</div>`
const detailWraper = document.querySelector('.glass-wrapper')
detailWraper.innerHTML = str
// 数据动态渲染完成后,再操作放大镜节点
let glass = new Glass('#glass1')
glass.setScale()
glass.onGlass()
glass.onTab(product)
}
getProductDetail()
</script>
/**
* 放大镜类
*/
class Glass {
constructor(id) {
this.rootEle = document.querySelector(id)
this.mask = this.rootEle.querySelector('.mask') //mask遮罩层
this.showBox = this.rootEle.querySelector('.m-left') //showbox显示盒子
this.glassBox = this.rootEle.querySelector('.right-wraper') // 放大镜glassBox
this.bgPic = this.rootEle.querySelector('.right-wraper>img') //背景图bgpic
this.ulLis = this.rootEle.querySelectorAll('.left-wraper ul>li')
this.showBoxPic = this.showBox.querySelector('img')
}
/**
* 计算放大镜图片的比例
* 目的: 遮罩层区域遮罩区域大小 与 放大镜放大区域大小相同
* 遮罩层mask 放大镜
* -------------- = -----------------
* 显示盒子showBox 背景图 ?
* 背景图 = 放大镜* showBox / mask
*/
setScale() {
// 遮罩层mask
let maskW = parseInt(window.getComputedStyle(this.mask).width)
let maskH = parseInt(window.getComputedStyle(this.mask).height)
// 显示盒子showBox
let showBoxW = parseInt(window.getComputedStyle(this.showBox).width)
let showBoxH = parseInt(window.getComputedStyle(this.showBox).height)
// 放大镜glassBox
let glassBoxW = parseInt(window.getComputedStyle(this.glassBox).width)
let glassBoxH = parseInt(window.getComputedStyle(this.glassBox).height)
// 背景图
let bgPicW = (glassBoxW * showBoxW) / maskW
let bgPicH = (glassBoxH * showBoxH) / maskH
this.bgPic.style.width = bgPicW + 'px'
this.bgPic.style.height = bgPicH + 'px'
}
/**
* 遮罩层移光标移动
* offsetX offsetY 相对自身
* clientX clientY 浏览器
* pageX pageY 页面
*
* window.getComputedStyle(ele).width
* offsetWidth
* clientWidth
*/
onGlass() {
let _this = this
// 移入显示
this.showBox.addEventListener('mouseover',()=>{
this.mask.style.display = 'block'
this.glassBox.style.display = 'block'
})
// 移出隐藏
this.showBox.addEventListener('mouseout',()=>{
this.mask.style.display = 'none'
this.glassBox.style.display = 'none'
})
//showBox鼠标移动事件
this.showBox.addEventListener('mousemove', function (e) {
e = e || window.event
let x = e.offsetX - _this.mask.clientWidth / 2
let y = e.offsetY - _this.mask.clientHeight / 2
// 边界检查
if (x < 0) {
x = 0
}
if (x > _this.showBox.clientWidth - _this.mask.clientWidth) {
x = _this.showBox.clientWidth - _this.mask.clientWidth
}
if (y < 0) {
y = 0
}
if (y > _this.showBox.clientHeight - _this.mask.clientHeight) {
y = _this.showBox.clientHeight - _this.mask.clientHeight
}
// 移动遮罩层
_this.mask.style.left = x + 'px'
_this.mask.style.top = y + 'px'
// 移动背景图片
/*
遮罩层 遮罩层移动距离
------ = -----------------
放大镜 背景图移动距离?
背景图移动距离= 遮罩层移动距离*放大镜/遮罩层
*/
// 遮罩层mask
let maskW = parseInt(window.getComputedStyle(_this.mask).width)
let maskH = parseInt(window.getComputedStyle(_this.mask).height)
// 放大镜glassBox
let glassBoxW = parseInt(window.getComputedStyle(_this.glassBox).width)
let glassBoxH = parseInt(window.getComputedStyle(_this.glassBox).height)
let moveX = x * glassBoxW / maskW
let moveY = y * glassBoxH / maskH
_this.bgPic.style.left = -moveX + 'px'
_this.bgPic.style.top = -moveY + 'px'
})
}
/**
* 切换图片
*/
onTab(product){
let _this = this
for(let i = 0; i < this.ulLis.length; i++){
this.ulLis[i].addEventListener('mouseover',function(){
// 清除所有选中效果
_this.onClear()
// 当前选设置选中效果
this.className = 'active'
// 显示盒子图片
_this.showBoxPic.setAttribute('src',`${product.list[i]}`)
// 背景图片切换
_this.bgPic.setAttribute('src',`${product.list[i]}`)
})
}
}
onClear(){
for(let i = 0; i < this.ulLis.length; i++){
this.ulLis[i].className = ''
}
}
}
封装ajax promise:
function myPromise(options) {
return new Promise((resolve, reject) => {
ajax({
method: options.method,
url: options.url,
data: options.data,
success: function (result) {
resolve(result)
},
fail: function (error) {
reject(error)
},
})
})
}
function ajax(options) {
// 1. 创建XMLHttpRequest
let xhr = new XMLHttpRequest()
let param = formateParam(options.data) // name=jack&age=18
let method = options.method.toUpperCase()
// 2. 建立连接
if (method == 'GET') {
xhr.open(options.method, options.url + '?' + param)
// 3. 发送请求
xhr.send()
} else if (method == 'POST') {
xhr.open(options.method, options.url)
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
xhr.send(param)
}
// 4. 接收响应数据
xhr.onreadystatechange = function () {
// 4.1 是否响应完成
if (xhr.readyState === 4) {
// 4.2 是否成功响应
if (xhr.status === 200) {
let data = xhr.responseText // 响应内容
data = JSON.parse(data)
options.success(data)
} else {
alert('网络出错 ' + xhr.status)
}
}
}
}
/**
* 格式化参数
* {name:'jack',age:18} => name=jack&age=18
* 遍历对象,属性转换成名称=值形式,存储到数组, 再将数组元素用&符号拼接join('&)
* ['name=jack','age=18'] ->
*/
function formateParam(obj) {
let arr = []
for (const key in obj) {
let item = `${key}=${obj[key]}` // name=jack age=18
arr.push(item) // ['name=jack','age=18;]
}
return arr.join('&') // name=jack&age=18
}
promise三种状态
pending(进行中)、fulfilled(已成功)和rejected(已失败)
- 对象的状态不受外界影响。Promise对象代表一个异步操作,只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变,就不会再变:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
Promise类对象方法
- 类对象 Person
- 实例对象 new Person('jack',18)
- 原型对象Person.prototype
- new Promise().then().catch() [实例对象的方法]
//已引入封装promise.js let promise1 = myPromise({ method: 'get', url: 'http://10.7.162.150:8089/api/shop/list', }) promise1.then(res=>{ console.log('商品列表',res); }) // 获取bannber轮播列表 let promise2 = myPromise({ method: 'get', url: 'http://10.7.162.150:8089/api/shop/banner', }) promise2.then(res=>{ console.log('bannber列表 ',res); })
Promise类对象方法不用定义实例对象(new Promise())
1.Promise.all([promise1,promise2...])
=>Promise对象 包含数组中所有promise对象执行的结果
let promise1 = myPromise({
method: 'get',
url: 'http://10.7.162.150:8089/api/shop/list',
})
let promise2 = myPromise({
method: 'get',
url: 'http://10.7.162.150:8089/api/shop/banner',
})
Promise.all([promise1, promise2]).then(res => console.log('res >> ', res))
2.Promise.race([promise1,promise2...]).then(res=>{})
=>竞争
=>最先执行完的异步promise结果
Promise.race([promise1, promise2]).then(res => console.log(res))
3.Promise.reject('失败').catch(error=>{})
Promise.resolve('成功').then(res=>console.log(res))
4.Promise.resolve('成功').then(res=>{})
Promise.reject('失败').then(null,error=>console.log(error))
Promise.reject('失败').catch(error=>console.log(error))
// 满足条件返回promise对象
function test(){
if(true){
// new Promise(()=>{ })
return Promise.resolve('成功')
}else{
Promise.reject('失败')
}
}
本地存储 Storage
本地存储 Storage
电脑硬盘 存储化存储数据
电脑内存 临时数据 -电脑关机或者程序终止数据消失
locationStorage对象
locationStorage.setItem(key1,value1) //存储一条数据到locationStorage
locationStorage.setItem(key2,value2) //存储一条数据到locationStorage
let value1 = locationStorage.getItem(key1) //获取locationStorage数据
function test1() {
localStorage.setItem('num', 100) // 向localStorage存key为num值为100的一条数据
localStorage.setItem('state', true) // 向localStorage存key为state值为true的一条数据
let num1 = localStorage.getItem('num')
let state = localStorage.getItem('state')
console.log('获取num值是 ', typeof num1)
console.log('state类型 ', typeof state, ' state :', state)
if (state) {
console.log('成立')
} else {
console.log('不成立')
}
// 取对象
}
test1()
locationStorage.removeItem(key) //移出key对应数据
clear() //清空所有数据
function test3() {
let newProudct1 = {
id: 1001,
name: 'javascript高级编程',
url: 'https://img2.baidu.com/it/u=544283419,3814727158&fm=253&fmt=auto&app=120&f=JPEG?w=477&h=307',
price: 100,
num: 0,
}
// 商品存储到数组,将数组持久化存储到localStorage,一条一条存储
let list = localStorage.getItem('list') || '[]' // 如果localStorage没有存储过商品返回空数组
list = JSON.parse(list)
list.push(newProudct1)
localStorage.setItem('list', JSON.stringify(list))
// 添加第二条商品
let newProudct2 = {
id: 1002,
name: 'vue高级编程',
url: 'https://img0.baidu.com/it/u=213764802,1949531026&fm=253&fmt=auto&app=138&f=JPEG?w=417&h=236',
price: 100,
num: 0,
}
let list1 = localStorage.getItem('list') || '[]'
list1 = JSON.parse(list1)
list1.push(newProudct2)
localStorage.setItem('list', JSON.stringify(list1))
}
test3()
key 类型 字符串类型
value 字符串
let obj = {name:'jack',age:18}
JSON.stringify(obj)
true -> 'true'
100 -> '100'
浏览器 application选项查看localStorage持久化存储的数据
function test3() {
let newProudct1 = {
id: 1001,
name: 'javascript高级编程',
url: 'https://img2.baidu.com/it/u=544283419,3814727158&fm=253&fmt=auto&app=120&f=JPEG?w=477&h=307',
price: 100,
num: 0,
}
// 商品存储到数组,将数组持久化存储到localStorage,一条一条存储
let list = localStorage.getItem('list') || '[]' // 如果localStorage没有存储过商品返回空数组
list = JSON.parse(list)
list.push(newProudct1)
localStorage.setItem('list', JSON.stringify(list))
// 添加第二条商品
let newProudct2 = {
id: 1002,
name: 'vue高级编程',
url: 'https://img0.baidu.com/it/u=213764802,1949531026&fm=253&fmt=auto&app=138&f=JPEG?w=417&h=236',
price: 100,
num: 0,
}
let list1 = localStorage.getItem('list') || '[]'
list1 = JSON.parse(list1)
list1.push(newProudct2)
localStorage.setItem('list', JSON.stringify(list1))
}
test3()
购物车3.0 localStorage中持久化存储
<div class="containter">
<table>
<!-- 动态渲染 -->
</table>
</div>
<!-- 商品表单 -->
<div class="prowraper">
<form>
<input type="text" name="name" placeholder="请输入商品名"><br/>
<input type="text" name="price" placeholder="请输入商品价格"> <br/>
<input type="text" name="num" placeholder="请输入商品数量"> <br/>
<input type="text" name="url" placeholder="请输入商品图片地址"> <br/>
<input type="submit" id="confirm" value="添加商品">
</form>
</div>
<script src="./js/cart.js"></script>
/**
* 1. 显示商品列表
* => 动态渲染localStorage中持久化存储的商品列表数据
*/
function showProductList(){
let listStr = localStorage.getItem('list') || '[]'
list = JSON.parse(listStr) // 商品列表
let str = `<tr>
<th>序列号</th>
<th>商品图片</th>
<th>商品信息</th>
<th>单价</th>
<th>数量</th>
<th width="100px">总价</th>
<th>操作</th>
</tr>`
let arr = list.map(item=>{
return `<tr>
<td>${item.id}</td>
<td><img src="${item.url}" alt="pic1"/></td>
<td>${item.name}</td>
<td>${item.price}</td>
<td><input type="button" value="-" name="minus" ${item.num == 0 ? 'disabled' : ''} data-id="${
item.number
}"/><input type="text" value="${item.num}" name="amount"/><input
type="button"
value="+"
name="plus"
data-id="${item.number}"
/></td>
<td>${item.num * item.price}</td>
<td>移入收藏<br /><a href="javascript:void(0)" class="del" data-id="${item.id}">删除</a></td>
</tr>`
})
const tableEle = document.querySelector('table')
tableEle.innerHTML = str + arr.join('')
}
/**
* 绑定添加商品事件
*/
function bindAddProduct() {
const formEle = document.querySelector('form')
const nameInput = document.querySelector('input[name="name"]')
const priceInput = document.querySelector('input[name="price"]')
const numInput = document.querySelector('input[name="num"]')
const urlInput = document.querySelector('input[name="url"]')
formEle.addEventListener('submit', function (e) {
e = e || window.event
e.preventDefault() // 阻止默认行为
let name = nameInput.value // 商品名称
let price = priceInput.value // 商品价格
let num = numInput.value // 商品数量
let url = urlInput.value // 商品地址
addProduct(name, price, num, url)
// 清空表单数据
nameInput.value = ''
priceInput.value = ''
numInput.value = ''
urlInput.value = ''
})
}
function addProduct(name,price,num,url){
let id = getRandom(1000, 10000) // 随机生成4位商品序号
// 持久化存储商品到localStorage
let listStr = localStorage.getItem('list') || '[]'
let list = JSON.parse(listStr)
list.push({
id,
name,
price,
num,
url
})
//持久化存储到localStorage
localStorage.setItem('list',JSON.stringify(list))
showProductList()
}
/*
* 返回m到n之间的随机数
*/
function getRandom(x, y) {
var n = Math.max(x, y)
var m = Math.min(x, y)
return Math.floor(Math.random() * (n - m) + m)
}
showProductList()
bindAddProduct()