getJson('api/a.json',function(){})
// 若上面的函数发生错误 我们无法使用try catch 捕获错误
// 不能这样使用
try{
getJson('api/a.json',function(){})
}catch(err=>{
console.log(err)
})
// 原因 是回调函数和开始任务中这段代码不在同一个事件循环步骤
这个很常见,比如一个场景,我们需要先拿到用户信息调用a接口,在用户信息的基础上我们需要获取用户的课程调用b接口,拿到用户的课程后我们需要判断该课程是否过期调用c接口
回调地狱产生
比如 我们需要从三个接口分别获取三份数据,然后在某个方法中同时使用这个三个数据,
由于我们不知道,数据返回的先后,只能分别在获取三分数据的接口中去调用封装好的函数去同时使用这三份数据。
可以简单的理解为对于异步任务结果的一个占位符。我现在还没拿到数据,但是我将来会得到。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>promise执行顺序title>
head>
<body>
<script>
console.log('start code');
const aPromise = new Promise((resolve, reject) => {
console.log('进入a promise');
// 这里模拟一个异步请求
setTimeout(() => {
console.log('进入a promise 定时器');
resolve('a promise 成功');
}, 500);
});
aPromise
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
const bPromise = new Promise((resolve, reject) => {
console.log('进入b promise');
resolve('b promise 成功');
});
bPromise
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
console.log('end code');
script>
body>
html>
结果
start code
pro.html:12 进入a promise
pro.html:29 进入b promise
pro.html:41 end code
pro.html:35 b promise 成功
pro.html:15 进入a promise 定时器
pro.html:22 a promise 成功
显示拒绝是我们手动调用reject函数
隐式拒绝是业务代码发生异常错误
相对callback会好一些 但是还不是最完美方案(后面的aysnc/await 是同步书写的执行异步方法的完美方案)
getJson('api/a.json')
.then(user=>getJson(user[0].courseUrl))
.then(course=>getJson(canuseUrl))
.catch(e=>{
console.log(e)
}))
当所有的子Promise都完成,该Promise完成,返回值是全部值的数组。
如果有任何一个失败,该Promise失败,返回值是第一个失败的子Promise的结果。
Promise.all([getJson('api/a,json'),
getJson('api/b,json'),
getJson('api/c,json')]).then(res=>{
const a = res[0];
const b = res[1];
const c = res[2];
}).catch(e=>{
console.log(e)
})
它有任意一个返回成功后,就算完成,但是 进程不会立即停止
Promise.race([getJson('api/a,json'),
getJson('api/b,json'),
getJson('api/c,json')]).then(res=>{
if(res !== null){
//执行操作
}
}).catch(e=>{
console.log(e)
})
把异步操作和定时器放到一起,如果定时器先触发,认为超时,告知用户
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功了')
}, 2000);
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 5000);
})
Promise.race([p1, p2]).then((result) => {
console.log(result) //['成功了', 'success']
}).catch((error) => {
console.log(error)
})
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>promise 封装异步请求title>
head>
<body>
<script>
function getData(url) {
const promise = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = function () {
try {
if (xhr.status === 200) {
console.log(xhr.responseText);
resolve(xhr.responseText);
} else {
reject(xhr.status);
}
} catch (error) {
reject(error.status);
}
};
xhr.onerror = function () {
reject(xhr.status);
};
xhr.send(null);
});
return promise;
}
let url = 'http://127.0.0.1:8881';
getData(url)
.then((res) => {
const data = JSON.parse(res);
console.log(data.a);
return data;
})
// 注意这里的链式调用 需要上面的then 返回值才行
.then((data) => {
console.log(data);
})
.catch((err) => {
console.log(err);
});
script>
body>
html>
/**
* promsie 主要有7个属性
* state 状态
* value 成功返回值
* reson 错误信息
* resolve 方法 执行成功调用
* reject 方法 执行失败调用
* then 方法
* **/
// 简单版本
function myPromise(constructor) {
let self = this;
self.status = 'pending';
self.value = undefined;
self.reason = undefined;
function resolve(value) {
if (self.status === 'pending') {
self.value = value;
self.status = 'fulfilled';
}
}
function reject(reason) {
if (self.status === 'pending') {
self.value = reason;
self.status = 'rejected';
}
}
// 捕获构造异常
try {
constructor(resolve, reject);
} catch (e) {
reject(e);
}
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
let self = this;
switch (self.status) {
case 'fulfilled':
onFulfilled(self.value);
break;
case 'rejected':
onRejected(self.reason);
break;
default:
}
};
// 测试
let p = new myPromise((resolve, reject) => {
resolve(1);
});
p.then((res) => {
console.log(res);
});
参考: