出现原由
先看一个例子:
模拟发送表白信息,如果一个失败,那么再给其他人发送,这时就相当于在失败回调函数中套了一层回调;如果后续还有多个表白对象,那么将一层一层地嵌套下去,也就是回调地狱。
/**
* 模拟发送表白信息
* @param name 表白对象名字
* @param onFulfilled 成功回调
* @param onRejected 失败回调
*/
function sendMessage(name, onFulfilled, onRejected) {
// 发送表白信息
console.log(`小丑丑 -> ${name}: 我有一件重要的事想对你说,我喜欢你!`)
console.log(`等待${name}回复...`)
// 模拟女生回复
setTimeout(()=> {
// 有百分之十概率成功
if (Math.random() <= 0.1) {
onFulfilled(`${name} -> 小丑丑:我们在一起吧~`)
} else {
onRejected(`${name} -> 小丑丑:你是个好人,但是我们不合适。`)
}
}, 1000)
}
sendMessage('白月光', message => {
console.log('成功:', message)
}, message => {
console.log('失败:', message)
})
Promise 规范
Promise 是一套专门处理异步场景的规范,它能有效的避免回调地狱的产生,使异步代码更加清晰、简洁、统一。
Promise A+规定:
-
所有的异步场景,都可以看作是一个异步任务,每个异步任务,在 js 中应该表现为一个对象(比如上面的 sendMessage )该对象称为Promise对象,也叫做任务对象,例如远程登录、延时弹窗。
-
每个任务对象(Promise),都应该有两个阶段、三个状态。
unsettled(pending) -> settled(fulfilled / rejected)
- 挂起 -> 完成 :resolve(message)
- 挂起 -> 失败 :reject(error)
-
对于任务的后续处理,完成状态的后续为 onFulfilled,失败的后续处理为 onRejected。
练习
延迟执行函数
/**
* 延迟执行函数
* @param duration 延迟时间(单位:毫秒)
* @returns {Promise<unknown>} 返回任务对象
*/
function delay(duration) {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, duration)
})
}
delay(1000).then(() => {
console.log('1 second later')
})
元素创建
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<style>
</style>
<body>
<div class="container"></div>
<div class="label"></div>
<script>
//根据指定的图片路径,创建一个img元素
//该函数需要返回一个Promise,当图片加载完成后,任务完成,若图片加载失败,任务失败
//任务完成后,需要提供的数据是图片D0M元素;任务失败时,需要提供失败的原因
//提示:img元素有两个事件,1oad事件会在图像加载完成时触发,error事件会在图像加载失败时触发
function createImg(imgUrl) {
return new Promise((resolve, reject) => {
let img = document.createElement('img')
img.src = imgUrl
img.onload = () => {
resolve(img)
}
img.onerror = (event) => {
reject(event)
}
})
}
// 有无防盗链
const imgError = 'https://bkimg.cdn.bcebos.com/pic/86d6277f9e2f070828386172686eaf99a9014c085424?x-bce-process=image/format,f_auto/resize,m_lfit,limit_1,h_460'
const imgSuccess = 'https://img.zcool.cn/community/011a5357b64c620000018c1b9e7e67.png@2o.png'
// createImg(imgSuccess)
//使用createImage函数创建一个图像,图像路径自行定义
//当图像成功加载后,将图像宽高显示在元素中,当图像加载失败后,输出加载失败的原因
createImg(imgError).then((img) => {
const p = document.querySelector('.label')
p.innerHTML = `图像的宽高分别为:${img.width} - ${img.height}`
}, (error) => {
console.log(error)
})
//使用createImage函数创建一个图像,图像路径自行定义
//当图像成功加载后,将图像元素加入到container容器中,当图像加载失败后,输出加载失败的原因
createImg(imgSuccess).then((img) => {
const container = document.querySelector('.container')
container.appendChild(img)
}, (error) => {
console.log(error)
})
</script>
</body>
</html>