promise前身
异步加载图片体验JS任务操作
function loadImage(src, resolve, reject) {
let image = new Image()
image.src = src
image.onload = () => {
resolve(image)
};
image.onerror = reject
}
loadImage("images/1.jpg",(image) => {
console.log('图片加载完成');
document.body.appendChild(image)
}, () => {
console.log('图片加载失败');
})
console.log('sss');
定时器的任务轮询
<style>
div {
width: 100px;
height: 100px;
background-color: aqua;
left: 0;
position: absolute;
}
</style>
<div></div>
<script>
function interval(cb, delay = 100) {
let id = setInterval(() => cb(id), delay);
}
// interval(function(id){
// console.log(id);
// }, 1000)
interval((timeId) => {
const div = document.querySelector('div')
let left = parseInt(window.getComputedStyle(div).left)
console.log(left);
div.style.left = left + 10 + 'px'
if (left >= 200) {
clearInterval(timeId)
interval((timeId)=>{
let width = parseInt(window.getComputedStyle(div).width)
div.style.width = width - 10 + 'px'
if(width <= 20) {
clearInterval(timeId)
}
}, 100)
}
})
console.log('哈哈哈哈哈哈或');
// for(let i = 0; i< 100000;i++){
// console.log(i);
// }
// 主线程执行完了,才会轮询任务队列
</script>
通过文件依赖了解任务排序
// hd.js
function hd(){
console.log('hd.js)
}
// houdunren.js
function houdunren(){
hd()
console.log('houdunren.js)
}
/**
* 先进先执行
* 文件 --- 文件加载模块 --- 加载完 ---- 任务队列
* 主进程执行完毕后,才会执行任务队列
* 多个文件在文件加载模块中没有队列的特性,加载完毕就放入任务队列中,所以会有出错的情况,
* houdunren.js中引用了hd.js,如果houdunren.js先执行完,那么会报错: houdunren.js:2 Uncaught ReferenceError: hd is not defined
* */
function load(src, resolve) {
let script = document.createElement('script')
script.src = src
script.onload = resolve
document.body.appendChild(script)
}
load('JS/hd.js', () => {
hd()
})
load('JS/houdunren.js', () => {
houdunren()
})
console.log('我先走一步');
-----> 解决
function load(src, resolve) {
let script = document.createElement('script')
script.src = src
script.onload = resolve
document.body.appendChild(script)
}
load('JS/hd.js', () => {
// hd.js加载完毕再去处理下面的
load('JS/houdunren.js', () => {
houdunren()
})
})
console.log('我先走一步');
问题: 会存在大量的嵌套,导致回调地狱
promise微任务处理机制
/**
* pending 准备阶段
* resolve 成功状态
* reject 失败/拒绝状态
*
*/
/**
* 任务队列
* 微任务队列
* 宏任务队列
* 先执行微任务,再执行宏任务
*/
let p1 = new Promise((resolve, reject) => {
// resolve('成功')
reject('拒绝')
}).then(res => {
console.log(res);
}, err => {
console.log(err);
})
console.log(p1);
宏任务与微任务执行顺序
/**
* 同步任务----微任务-----宏任务
* */
setTimeout(() => {
console.log('setTimeout');
}, 0)
new Promise((resolve, reject) =>{
resolve()
console.log('promise');
}).then(res => console.log('成功'));
console.log('东酥');
宏任务的提升误解
let promise = new Promise((resolve, reject) => {
/**
* 微任务是宏任务执行完成才被创建
*
*/
setTimeout(() => {
resolve()
console.log('settimeout2');
}, 0);
console.log('promise');
}).then(res => console.log('成功'))
console.log('dongsu');
Promise单一状态和状态中转
let p1 = new Promise((resolve, reject) => {
// resolve('成功')
// reject('失败')
setTimeout(() => {
reject('失败')
}, 2000);
})
new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve('fulfilled')
// }, 1000);
resolve(p1) // 下面的状态受p1状态的影响
}).then(
msg => {
console.log(msg);
},
error => {
console.log('error', error);
}
)
console.log('dongsu');
/**
* 主线程----轮询微任务,执行-----
* Promise状态改变才会产生微任务
* promise只要状态改变,后面就是无法更改的
*/
new Promise((resolve, reject) => {
// setTimeout(() => {
// resolve('fulfilled')
// }, 1000);
resolve('fulfilled')
reject('失败')
}).then(
msg => {
console.log(msg);
},
error => {
console.log('error', error);
}
)
console.log('dongsu');
了解Promise.then的基本语法
一个promise需要提供一个
then方法访问promise结果,then用于定义当promise状态发生改变时的处理,即promise处理异步操作,then用于结果
- then方法必须返回promise,用户返回或系统自动返回
- 第一个函数在
resolved状态时执行,即执行resolve时执行then第一函数处理成功状态 - 第二个函数在
rejected状态时执行,即执行reject时执行第二个函数处理失败状态,该函数时可选的 - 两个函数都接收
promise传出的值做为参数 - 也可以使用
catch来处理失败的状态 - 如果then返回promise,下一个then会在当前promise状态改变后执行
链式调用
/**
* 主线程----微任务----宏任务
*
* **/
let p1 = new Promise((resolve, reject) => {
// resolve('fulfilled')
reject('rejected')
})
let p2 = p1.then(
res => console.log(res),
reason => console.log(reason)
).then(val => console.log('成功'), err => console.log(err))
// console.log(p1);
// console.log(p2);
setTimeout(() => {
console.log(p1);
console.log(p2);
}, 0);
then是对上个promise 的rejected的处理,每个then会是一个新的promise,默认传递fulfilled状态
then返回值的处理技巧
// let p1 = new Promise((resolve, reject) =>{
// resolve('fulfilled')
// }).then(
// value => console.log(value),
// reason => console.log(reason)
// )
let p1 = new Promise((resolve, reject) => {
resolve('fulfilled')
}).then(
value => {
// 如果不return,下一个then就是对上一个then返回的promise处理,而不是下面的Promise处理
// return 'dongsu' // 返回普通值,下一个then的参数可以直接接收到这个值
// 独立的Promise发生错误,需要对其进行处理
// new Promise((resolve, reject) => {
// setTimeout(() => {
// // resolve('处理完成')
// reject('处理错误')
// }, 0);
// }).then(null, ()=>{})
return new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('处理完成')
reject('处理错误')
}, 0);
}).then(null, () => {
// return 'aaaa'
return new Promise((resolve, reject) => {
reject('失败了')
})
})
},
reason => console.log(reason)
).then(value => console.log('res1', value), err => console.log('err1', err))
// 只要return Promise,后面的then就是对前面返回的promise的处理
其他类型的Promise封装
let p1 = new Promise((resolve, reject) => {
resolve('fulfilled')
}).then(
value => {
// 类型1
// return new Promise((resolve, reject) => {
// resolve('成功1')
// })
// 类型2
// return {
// then(resolve, reject) {
// setTimeout(() => {
// resolve('这是对象2');
// }, 2000);
// }
// }
// 类型3
// class DS {
// then(resolve, reject) {
// setTimeout(() => {
// resolve('这是对象3');
// }, 2000);
// }
// }
// return new DS()
// 类型4
return class {
static then(resolve, reject) {
// resolve('成功---这是一个静态方法')
resolve('失败---这是一个静态方法')
}
}
},
reason => console.log(reason)
).then(
value => console.log(value),
reason => console.log(reason)
)
使用promise封装ajax异步请求
// function ajax(url, cb) {
// let xhr = new XMLHttpRequest();
// xhr.open('GET', url);
// xhr.send()
// xhr.onload = function () {
// if (this.status === 200) {
// cb(JSON.parse(this.response))
// // console.log(this.response);
// } else {
// throw new Error('加载失败')
// }
// }
// }
function ajax(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send()
xhr.onload = function () {
if (this.status === 200) {
resolve(JSON.parse(this.response))
} else {
reject('加载失败')
}
}
xhr.onerror = function () {
reject(this)
}
})
}
catch
// new Promise((resolve, reject) => {
// resolve('fulfilled')
// // reject('rejected')
// // reject(new Error('promise fail'))
// // throw new Error('错误')
// // hd + 1;
// }).then(
// value => {
// return new Promise((resolve, reject) => {
// // hd+2;
// // resolve('成功')
// reject('失败')
// })
// },
// reason => console.log('rea1', reason)
// ).then(
// value => console.log('val2', value),
// reason => console.log('rea2', reason)
// )
new Promise((resolve, reject) => {
resolve('fulfilled')
// reject('rejected')
// reject(new Error('promise fail'))
// throw new Error('错误')
// hd + 1;
}).then(
value => {
return new Promise((resolve, reject) => {
// hd+2;
// resolve('成功')
reject('失败')
})
},
).then(
value => console.log('val2', value)
).catch(error => {
console.log('err', error);
})
- 将
catch放在最后面用于统一处理前面发生的错误
自定义错误处理
// console.dir(Error);
// let err = new Error('格式错误')
// console.log(err);
class ParamError extends Error {
constructor(msg) {
super(msg)
this.name = 'ParamError'
}
}
class HttpError extends Error {
constructor(msg) {
super(msg)
this.name = 'HttpError'
}
}
function ajax(url) {
return new Promise((resolve, reject) => {
if (!/^http/.test(url)) {
throw new ParamError('请求地址格式错误')
}
let xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.send()
xhr.onload = function () {
if (this.status === 200) {
resolve(JSON.parse(this.response))
} else if (this.status === 404) {
// 不能直接抛出 new HttpError('用户不存在'),因为网络请求是异步的
reject(new HttpError('用户不存在'))
} else {
reject('加载失败')
}
}
xhr.onerror = function () {
reject(this)
}
})
}
<script src="./JS/ajax.js"></script>
<script>
let url = `http://localhost:8080/php`
ajax(`${url}/user.php?name=后盾人`).then(
user => ajax(`${url}/houdunren.php?id=${user.id}`)
).then(lessons => console.log(lessons)).catch(err => {
console.log('err', err);
if(err instanceof ParamError) {
console.log(err.message);
}
if(err instanceof HttpError) {
alert(err.message);
}
})
</script>
finally
const promise = new Promise((resolve, reject) => {
reject('fail')
})
.then(msg => {
console.log('resolve');
})
.catch(error => {
console.log('error-catch', error);
})
.finally(() => {
console.log('永远会执行');
})
应用场景:loading加载效果,无论请求成功失败与否,最后加载都要结束
promise异步加载图片
function loadImage(src) {
return new Promise((resolve, reject) => {
const image = new Image()
image.src = src;
image.onload = () => {
resolve(image)
}
image.onerror = reject;
document.body.appendChild(image)
})
}
loadImage('images/1.jpg').then(image => {
image.style.border = 'solid 6px red'
})
封装setTimeout定时器
function timeout(delay = 1000) {
return new Promise(resolve => setTimeout(resolve, delay))
}
timeout(2000)
.then(() => {
console.log('domgsin.com');
return timeout(2000)
})
.then(value => {
console.log('hdsci.com');
})
构建扁平化的setInterval
div {
width: 100px;
height: 100px;
background-color: aqua;
left: 0;
position: absolute;
}
function interval(delay = 1000, cb) {
return new Promise(resolve => {
let id = setInterval(() => {
cb(id, resolve)
}, delay);
})
}
interval(100, (id, resolve) => {
const div = document.querySelector('div')
let left = parseInt(window.getComputedStyle(div).left)
console.log(left);
div.style.left = left + 10 + 'px'
if (left >= 200) {
clearInterval(id)
resolve(div)
}
}).then(div => {
console.log(div);
return interval(100, (id, resolve) => {
let width = parseInt(window.getComputedStyle(div).width)
div.style.width = width - 10 + 'px'
if (width <= 20) {
clearInterval(id)
resolve(div)
}
})
}).then(div => {
div.style.backgroundColor = 'red'
})
script脚本的Promise加载引擎
function loadScript(src) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = src;
script.onload = () => resolve(script);
script.onerror = reject;
document.body.appendChild(script);
})
}
loadScript('JS/hd.js').then(script => {
console.log(script);
return loadScript('JS/houdunren.js')
}).then(script => {
console.log(script);
houdunren()
}).catch(err => {
console.log(err);
})
Promise.resolve
function hd() { }
/*
函数也是对象
可以往里面压属性
*/
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://localhost:8888/php/user.php?name=${name}`).then(user => {
cache.set(name, user)
console.log('没走缓存');
return user
})
}
query('后盾人').then(user => {
console.log(user);
})
query('后盾人').then(user => {
console.log(user);
})
setTimeout(() => {
query('后盾人').then(user => {
console.log(user);
})
}, 1000);
/*
Promise.resolve()
*/
Promise.hd = function (value) {
return new Promise((resolve, reject) => {
resolve()
})
}
console.log(Promise.hd('后端人'));
// console.log(Promise.resolve('后盾人'));
// Promise.resolve('后盾人').then(value => {
// console.log(value);
// })
Promise.reject
let hd = {
then(resolve, rejecy) {
resolve('学习')
}
}
Promise.resolve(hd).then(value => {
console.log(value);
})
Promise.reject('fail').then(value => {
console.log(value);
}).catch(err => {
console.log(err);
})
new Promise((resolve, reject) => {
resolve('bu成功')
}).then(value => {
console.log(value);
if(value != '成功') {
// throw new Error('fail')
return Promise.reject('参数错误')
}
}).catch(err => {
console.log(err);
})
// new Promise((resolve, reject) => {
// resolve('成功')
// }).then(value => {
// console.log(value);
// }).catch(err => {
// console.log(err);
// })
Promise.all批量获取数据
const p1 = new Promise((resolve, reject) => {
// resolve('成功')
setTimeout(() => {
reject('fail')
}, 1000);
}).catch(err => {
// catch解决状态
console.log('p1', err);
})
const p2 = new Promise((resolve, reject) => {
// resolve('成功2')
setTimeout(() => {
resolve('成功2')
}, 1000);
})
Promise.all([p1, p2]).then(value => {
console.log(value);
}).catch(err => {
// 如果p1, p2的失败状态没有做处理,可以在all处使用catch进行错误处理
console.log('all', err);
})
// 应用场景
function getUsers(names) {
let promises = names.map(name => {
return ajax(`http://localhost:8888/php/user.php?name${name}`)
})
return Promise.all(promises)
}
getUsers(['后端人', '向军']).then(users => {
console.log(users);
})
Promise.allSettled
该Promise.allSettled() 方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。
allSettled 用于处理多个promise ,只关注执行完成,不关注是否全部执行成功,allSettled 状态只会是fulfilled。
const p1 = new Promise((resolve, reject) => {
resolve('resolved')
})
const p2 = new Promise((resolve, reject) => {
// resolve('resolved')
reject('fail')
})
/**
* Promise.allSettled
*
*/
Promise.allSettled([p1, p2]).then( results => {
console.log(results);
})
Promise.race
使用Promise.race() 处理容错异步,和race单词一样哪个Promise快用哪个,哪个先返回用哪个。
- 以最快返回的promise为准
- 如果最快返加的状态为
rejected那整个promise为rejected执行cache - 如果参数不是promise,内部将自动转为promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功1')
}, 3000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求超时')
}, 2000);
})
Promise.race([p1,p2]).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
Promise队列
实现原理
如果 then 返回promise 时,后面的then 就是对返回的 promise 的处理
let promise = Promise.resolve('好好学习')
promise.then(res => {
console.log(res);
return new Promise((resolve) => {
setTimeout(() => {
console.log('1');
resolve('成功2')
}, 2000);
})
}).then(res1 => {
console.log('res1', res1);
})
function queue(num) {
let promise = Promise.resolve()
num.map(v => {
promise = promise.then(_ => {
return v()
})
})
}
function p1() {
return new Promise(resolve => {
setTimeout(() => {
console.log('p1');
resolve()
}, 1000);
})
}
function p2() {
return new Promise(resolve => {
setTimeout(() => {
console.log('p2');
resolve()
}, 1000);
})
}
queue([p1, p2])
reduce封装Promise队列
function queue(num) {
num.reduce((promise, n) => {
return promise.then(_ => {
return new Promise(resolve => {
console.log(n);
setTimeout(() => {
resolve()
}, 1000);
})
})
}, Promise.resolve())
}
queue([1, 2, 3, 4, 5, 6])
使用队列渲染数据
class User {
constructor() { }
ajax(user) {
let url = `http://localhost:8888/php/user.php?name=${user}`;
return new Promise(resolve => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onload = function () {
if (this.status == 200) {
resolve(JSON.parse(this.response));
} else {
reject(this);
}
};
});
}
render(users) {
users.reduce((promise, user) => {
return promise.then(_ => {
return ajax(user)
}).then(user => {
return this.view(user)
})
}, Promise.resolve())
}
view(user) {
return new Promise(resovle => {
console.log(user);
let h2 = document.createElement('h2')
h2.innerHTML = user.name;
document.body.appendChild(h2)
resovle()
})
}
}
new User().render(['houdunren', 'dongsu'])
async/await
使用 async/await 是promise 的语法糖,可以让编写 promise 更清晰易懂,也是推荐编写promise 的方式。
async/await本质还是promise,只是更简洁的语法糖书写async/await使用更清晰的promise来替换 promise.then/catch 的方式
class User {
constructor(name){
this.name = name
}
then(resolve, reject) {
resolve()
}
}
async function get() {
await new User() // 这里执行了,才会继续往下走
console.log('打印11111111');
}
get()
class User {
constructor(name){
this.name = name
}
then(resolve, reject) {
let user = ajax(`http://localhost:8888/php/user.php?name=${this.name}`)
resolve()
}
}
async function get() {
let user = await new User('东酥') // 这里执行了,才会继续往下走
console.log('打印11111111', user);
}
get()
async和await的几种声明方法
// 方法一
let hd = {
async get(name) {
return await ajax(`http://localhost:8888/php/user.php?name=${name}`)
}
}
hd.get('houdunren').then(user => {
console.log(user);
})
// 方法二
async function get(name) {
let user = await ajax(`http://localhost:8888/php/user.php?name=${name}`)
}
get('houdunren').then(user => {
console.log(user);
})
// 方法三
class User {
async get(name) {
return await ajax(`http://localhost:8888/php/user.php?name=${name}`)
}
}
new User().get('houdunren').then(user => {
console.log(user);
})
async的错误处理
async function hd () {
// console.log(a);
throw new Error('fail')
}
hd().catch(err => {
console.log(err);
})
后盾人-async
学习笔记