出现原由
先看一个例子:
模拟发送表白信息,如果一个失败,那么再给其他人发送,这时就相当于在失败回调函数中套了一层回调;如果后续还有多个表白对象,那么将一层一层地嵌套下去,也就是回调地狱。
/*** 模拟发送表白信息* @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 = imgUrlimg.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>