Promise
定时器的ID可以传到回调函数内部
<style>
div {
width: 100px;
height: 100px;
background: yellowgreen;
position: absolute;
}
</style>
<body>
<div></div>
</body>
<script>
function interval(callback, delay = 100) {
let id = setInterval(() => callback(id), delay);
}
const div = document.querySelector("div");
interval(timeId => {
const left = parseInt(window.getComputedStyle(div).left);
div.style.left = left + 10 + "px";
if (left > 200) {
clearInterval(timeId);
interval(timeId => {
const width = parseInt(window.getComputedStyle(div).width);
div.style.width = width - 1 + "px";
if (width <= 0) clearInterval(timeId);
}, 10);
}
}, 100);
</script>异步状态
一个 promise 必须有一个 then 方法用于处理状态改变
Promise 包含pending、fulfilled、rejected三种状态
pending指初始等待状态,初始化promise时的状态resolve指已经解决,将promise状态设置为fulfilledreject指拒绝处理,将promise状态设置为rejectedpromise是生产者,通过resolve与reject函数告之结果promise非常适合需要一定执行时间的异步任务- 状态一旦改变将不可更改
- 每一个then()都是一个promise
- 下一个then()会接受到上一个的结果,没有then()处理就会报错。
promise 没有使用 resolve 或 reject 更改状态时,状态为 pending
promise 创建时即立即执行即同步任务,then 会放在异步微任务中执行,需要等同步任务执行后才执行。
let promise = new Promise((resolve, reject) => {
resolve("fulfilled");
console.log("lover");
});
promise.then(msg => {
console.log(msg);
});
console.log("jd.com");
//lover
//test.html:24 jd.com
//test.html:22 fulfilledpromise 的 then、catch、finally 的方法都是异步任务
then
一个 promise 需要提供一个 then 方法访问 promise 结果,then 用于定义当 promise 状态发生改变时的处理,即promise 处理异步操作,then 用于结果。
promise 就像 kfc 中的厨房,then 就是我们用户,如果餐做好了即 fulfilled ,做不了拒绝即rejected 状态。那么 then 就要对不同状态处理。
- then 方法必须返回 promise,用户返回或系统自动返回
- 第一个函数在
resolved状态时执行,即执行resolve时执行then第一个函数处理成功状态 - 第二个函数在
rejected状态时执行,即执行reject时执行第二个函数处理失败状态,该函数是可选的 - 两个函数都接收
promise传出的值做为参数 - 也可以使用
catch来处理失败的状态 - 如果
then返回promise,下一个then会在当前promise状态改变后执行
语法说明
then 的语法如下,onFulfilled 函数处理 fulfilled 状态, onRejected 函数处理 rejected 状态
- onFulfilled 或 onRejected 不是函数将被忽略
- 两个函数只会被调用一次
- onFulfilled 在 promise 执行成功时调用
- onRejected 在 promise 执行拒绝时调用
promise.then(onFulfilled, onRejected)基础知识
then 会在 promise 执行完成后执行,then 第一个函数在 resolve成功状态执行
const promise = new Promise((resolve, reject) => {
resolve("success");
}).then(
value => {
console.log(`解决:${value}`);
},
reason => {
console.log(`拒绝:${reason}`);
}
);then 中第二个参数在失败状态执行
const promise = new Promise((resolve, reject) => {
reject("is error");
});
promise.then(
msg => {
console.log(`成功:${msg}`);
},
error => {
console.log(`失败:${error}`);
}
);如果只关心成功则不需要传递 then 的第二个参数
const promise = new Promise((resolve, reject) => {
resolve("success");
});
promise.then(msg => {
console.log(`成功:${msg}`);
});如果只关心失败时状态,then 的第一个参数传递 null
const promise = new Promise((resolve, reject) => {
reject("is error");
});
promise.then(null, error => {
console.log(`失败:${error}`);
});promise 传向 then 的传递值,如果 then 没有可处理函数,会一直向后传递
let p1 = new Promise((resolve, reject) => {
reject("rejected");
})
.then()
.then(
null,
f => console.log(f)
);如果 onFulfilled 不是函数且 promise 执行成功, p2 执行成功并返回相同值
let promise = new Promise((resolve, reject) => {
resolve("resolve");
});
let p2 = promise.then();
p2.then()then()then()then().then(resolve => {
console.log(resolve);
});如果 onRejected 不是函数且 promise 拒绝执行,p2 拒绝执行并返回相同值
let promise = new Promise((resolve, reject) => {
reject("reject");
});
let p2 = promise.then(() => {});
p2.then(null, null).then(null, reject => {
console.log(reject);
});链式调用
每次的 then 都是一个全新的 promise ,默认 then 返回的 promise 状态是 fulfilled
let promise = new Promise((resolve, reject) => {
resolve("fulfilled");
}).then(resolve => {
console.log(resolve);
})
.then(resolve => {
console.log(resolve);
});每次的 then 都是一个全新的 promise ,不要认为上一个 promise 状态会影响以后 then 返回的状态
let p1 = new Promise(resolve => {
resolve();
});
let p2 = p1.then(() => {
console.log("后盾人");
});
p2.then(() => {
console.log("houdunren.com");
});
console.log(p1); // Promise {<resolved>}
console.log(p2); // Promise {<pending>}
# 再试试把上面两行放在 setTimeout里
setTimeout(() => {
console.log(p1); // Promise {<resolved>}
console.log(p2); // Promise {<resolved>}
});then 是对上个 promise 的rejected或者resolve 的处理,每个 then 会是一个新的 promise,默认传递 fulfilled状态
new Promise((resolve, reject) => {
reject();
})
.then(
resolve => console.log("fulfilled"),
reject => console.log("rejected")
)
.then(
resolve => console.log("fulfilled"),
reject => console.log("rejected")
)
.then(
resolve => console.log("fulfilled"),
reject => console.log("rejected")
);
# 执行结果如下
ejected
fulfilled
fulfilled如果内部返回 promise 时将使用该 promise
let p1 = new Promise(resolve => {
resolve();
});
let p2 = p1.then(() => {
return new Promise(r => {
r("jd.com");
});
});
p2.then(v => {
console.log(v); //jd.com
});如果 then 返回promise 时,后面的then 就是对返回的 promise 的处理,需要等待该 promise 变更状态后执行。
let promise = new Promise(resolve => resolve());
let p1 = promise.then(() => {
return new Promise(resolve => {
setTimeout(() => {
console.log(`p1`);
resolve();
}, 2000);
});
}).then(() => {
return new Promise((a, b) => {
console.log(`p2`);
});
});如果then返回 promise 时,返回的promise 后面的then 就是处理这个promise 的
如果不
return情况就不是这样了,即外层的then的promise和内部的promise是独立的两个 promise
new Promise((resolve, reject) => {
resolve();
})
.then(v => {
return new Promise((resolve, reject) => {
resolve("第二个promise");
}).then(value => {
console.log(value);
return value;
});
})
.then(value => {
console.log(value);
});这是对上面代码的优化,把内部的 then 提取出来
new Promise((resolve, reject) => {
resolve();
})
.then(v => {
return new Promise((resolve, reject) => {
resolve("第二个promise");
});
})
.then(value => {
console.log(value);
return value;
})
.then(value => {
console.log(value);
});其它类型
循环调用
如果 then 返回与 promise 相同将禁止执行
let promise = new Promise(resolve => {
resolve();
});
let p2 = promise.then(() => {
return p2;
}); // TypeError: Chaining cycle detected for promisepromise
如果返加值是 promise 对象,则需要更新状态后,才可以继承执行后面的 promise
new Promise((resolve, reject) => {
resolve(
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("解决状态");
}, 2000);
})
);
})
.then(
v => {
console.log(`fulfilled: ${v}`);
return new Promise((resolve, reject) => {
setTimeout(() => {
reject("失败状态");
}, 2000);
});
},
v => {
console.log(`rejected: ${v}`);
}
)
.catch(error => console.log(`rejected: ${error}`));Thenables
包含 then 方法的对象就是一个 promise ,系统将传递 resolvePromise 与 rejectPromise 做为函数参数
下例中使用 resolve 或在then 方法中返回了具有 then方法的对象
- 该对象即为
promise要先执行,并在方法内部更改状态 - 如果不更改状态,后面的
thenpromise 都为等待状态
new Promise((resolve, reject) => {
resolve({
then(resolve, reject) {
resolve("解决状态");
}
});
})
.then(v => {
console.log(`fulfilled: ${v}`);
return {
then(resolve, reject) {
setTimeout(() => {
reject("失败状态");
}, 2000);
}
};
})
.then(null, error => {
console.log(`rejected: ${error}`);
});包含 then 方法的对象可以当作 promise 来使用
class User {
constructor(id) {
this.id = id;
}
then(resolve, reject) {
resolve(ajax(`http://localhost:8888/php/houdunren.php?id=${this.id}`));
}
}
new Promise((resolve, reject) => {
resolve(ajax(`http://localhost:8888/php/user.php?name=loveagri`));
})
.then(user => {
return new User(user.id);
})
.then(lessons => {
console.log(lessons);
});当然也可以是类
new Promise((resolve, reject) => {
resolve(
class {
static then(resolve, reject) {
setTimeout(() => {
resolve("解决状态");
}, 2000);
}
}
);
}).then(
v => {
console.log(`fulfilled: ${v}`);
},
v => {
console.log(`rejected: ${v}`);
}
);如果对象中的 then 不是函数,则将对象做为值传递
new Promise((resolve, reject) => {
resolve();
})
.then(() => {
return {
then: "后盾人"
};
})
.then(v => {
console.log(v); //{then: "后盾人"}
});catch
下面使用未定义的变量同样会触发失败状态
let promise = new Promise((resolve, reject) => {
hd;
}).then(
value => console.log(value),
reason => console.log(reason)
);如果 onFulfilled 或 onRejected 抛出异常,则 p2 拒绝执行并返回拒因
let promise = new Promise((resolve, reject) => {
throw new Error("fail");
});
let p2 = promise.then();
p2.then().then(null, resolve => {
console.log(resolve + ",后盾人");
});catch 用于失败状态的处理函数,等同于 then(null,reject){}
- 建议使用
catch处理错误 - 将
catch放在最后面用于统一处理前面发生的错误
const promise = new Promise((resolve, reject) => {
reject(new Error("Notice: Promise Exception"));
}).catch(msg => {
console.error(msg);
});catch 可以捕获之前所有 promise 的错误,所以建议将 catch 放在最后。下例中 catch 也可以捕获到了第一个 then 返回 的 promise 的错误。
new Promise((resolve, reject) => {
resolve();
})
.then(() => {
return new Promise((resolve, reject) => {
reject(".then ");
});
})
.then(() => {})
.catch(msg => {
console.log(msg);
});错误是冒泡的操作的,下面没有任何一个then 定义第二个函数,将一直冒泡到 catch 处理错误
new Promise((resolve, reject) => {
reject(new Error("请求失败"));
})
.then(msg => {})
.then(msg => {})
.catch(error => {
console.log(error);
});catch 也可以捕获对 then 抛出的错误处理
new Promise((resolve, reject) => {
resolve();
})
.then(msg => {
throw new Error("这是then 抛出的错误");
})
.catch(() => {
console.log("33");
});catch` 也可以捕获其他错误,下面在 `then` 中使用了未定义的变量,将会把错误抛出到 `catch
new Promise((resolve, reject) => {
resolve("success");
})
.then(msg => {
console.log(a);
})
.catch(reason => {
console.log(reason);
});处理机制
在 promise 中抛出的错误也会被catch 捕获
const promise = new Promise((resolve, reject) => {
throw new Error("fail");
}).catch(msg => {
console.log(msg.toString()+"后盾人");
});可以将上面的理解为如下代码,可以理解为内部自动执行 try...catch
const promise = new Promise((resolve, reject) => {
try {
throw new Error("fail");
} catch (error) {
reject(error);
}
}).catch(msg => {
console.log(msg.toString());
});像下面的在异步中 throw 将不会触发 catch,而使用系统错误处理
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
throw new Error("fail");
}, 2000);
}).catch(msg => {
console.log(msg + "后盾人");
});下面在then 方法中使用了没有定义的hd函数,也会抛除到 catch 执行,可以理解为内部自动执行 try...catch
const promise = new Promise((resolve, reject) => {
resolve();
})
.then(() => {
hd();
})
.catch(msg => {
console.log(msg.toString());
});在 catch 中发生的错误也会抛给最近的错误处理
const promise = new Promise((resolve, reject) => {
reject();
})
.catch(msg => {
hd();
})
.then(null, error => {
console.log(error);
});事件处理
unhandledrejection事件用于捕获到未处理的 Promise 错误,下面的 then 产生了错误,但没有catch 处理,这时就会触发事件。该事件有可能在以后被废除,处理方式是对没有处理的错误直接终止。
window.addEventListener("unhandledrejection", function(event) {
console.log(event.promise); // 产生错误的promise对象
console.log(event.reason); // Promise的reason
});
new Promise((resolve, reject) => {
resolve("success");
}).then(msg => {
throw new Error("fail");
});图片加载
下面是异步加载图片示例
function loadImage(file) {
return new Promise((resolve, reject) => {
const image = new Image();
image.src = file;
image.onload = () => {
resolve(image);
};
image.onerror = reject;
document.body.appendChild(image);
});
}
loadImage("images/test.png").then(image => {
image.style.border = "solid 20px black";
console.log("宽度:" + window.getComputedStyle(image).width);
});定时器
下面是封装的timeout 函数,使用定时器操作更加方便
function timeout(times) {
return new Promise(resolve => {
setTimeout(resolve, times);
});
}
timeout(3000)
.then(() => {
console.log("3秒后执行");
return timeout(1000);
})
.then(() => {
console.log("执行上一步的promise后1秒执行");
});链式操作
语法介绍
对同一个 promise 的多个 then ,每个then 都得到了同一个 promise 结果,这不是链式操作,实际使用意义不大。
const promise = new Promise((resolve, reject) => {
resolve("lover");
});
promise.then(hd => {
hd += "-agri";
console.log(hd); //lover-agri
});
promise.then(hd => {
hd += "-go";
console.log(hd); //lover-go
});promise 中的 then 方法可以链接执行,then 方法的返回值会传递到下一个then 方法。
then会返回一个promise,所以如果有多个then时会连续执行then返回的值会做为当前promise的结果
下面是链式操作的 then,即始没有 return 也是会执行,因为每个then 会返回promise
new Promise((resolve, reject) => {
resolve("lover");
})
.then(hd => {
hd += "-gg";
console.log(hd); //gg-hdcms
return hd;
})
.then(hd => {
hd += "-dd";
console.log(hd); //gg-dd-houdunren
});then 方法可以返回一个promise 对象,等promise 执行结束后,才会继承执行后面的 then。后面的then 方法就是对新返回的promise 状态的处理
new Promise((resolve, reject) => {
resolve("第一个promise");
})
.then(msg => {
console.log(msg);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第二个promise");
}, 3000);
});
})
.then(msg => {
console.log(msg);
});链式加载
使用promise 链式操作重构前面章节中的文件加载,使用代码会变得更清晰
function load(file) {
return new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = file;
script.onload = () => resolve(script);
script.onerror = () => reject();
document.body.appendChild(script);
});
}
load("js/1.js")
.then(() => load("js/2.js"))
.then(() => zhixin());扩展接口
resolve
使用 promise.resolve 方法可以快速的返回一个 promise 对象
根据值返加 promise
Promise.resolve("love").then(value => {
console.log(value); //love
});下面将请求结果缓存,如果再次请求时直接返回带值的 promise
- 为了演示使用了定时器,你也可以在后台设置延迟响应
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(
response => {
cache.set(name, response);
console.log("没走缓存");
return response;
}
);
}
query("love").then(response => {
console.log(response);
});
setTimeout(() => {
query("lover").then(response => {
console.log(response);
});
}, 1000);如果是 thenable 对象,也就是可以带有then的对象,会将对象包装成 promise 处理,这与其他 promise 处理方式一样的
const hd = {
then(resolve, reject) {
resolve("love");
}
};
Promise.resolve(hd).then(value => {
console.log(value);
});reject
和 Promise.resolve 类似,reject 生成一个失败的promise
Promise.reject("fail").catch(error => console.log(error));下面使用 Project.reject 设置状态
new Promise(resolve => {
resolve("love");
})
.then(v => {
if (v != "dotohi.com") return Promise.reject(new Error("fail"));
})
.catch(error => {
console.log(error);
});all
使用Promise.all 方法可以同时执行多个并行异步操作,比如页面加载时同进获取课程列表与推荐课程。
- 任何一个
Promise执行失败就会调用catch方法 - 适用于一次发送多个异步操作
- 参数必须是可迭代类型,如 Array/Set
- 成功后返回
promise结果的有序数组
下例中当 first、second 两个 Promise 状态都为 fulfilled 时,hd 状态才为fulfilled。
const hdcms = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第一个Promise");
}, 1000);
});
const houdunren = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第二个异步");
}, 1000);
});
const hd = Promise.all([hdcms, houdunren])
.then(results => {
console.log(results);
})
.catch(msg => {
console.log(msg);
});利用数组构造传参,一次请求。
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(this);
}
};
});
}
const api = "http://localhost:8888/php";
const promises = ["love", "you"].map(name => {
return ajax(`${api}/user.php?name=${name}`);
});
Promise.all(promises)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});可以将其他非promise 数据添加到 all 中,它将被处理成 Promise.resolve
const promises = [
ajax(`${api}/user.php?name=1`),
ajax(`${api}/user.php?name=2`),
{ id: 3, name: "hdcms", email: "admin@hdcms.com" }
];如果某一个promise没有 catch 处理,将使用promise.all 的 catch 处理
let p1 = new Promise((resolve, reject) => {
resolve("fulfilled");
});
let p2 = new Promise((resolve, reject) => {
reject("rejected");
});
Promise.all([p1, p2]).catch(reason => {
console.log(reason);
});allSettled
allSettled 用于处理多个promise ,只关注执行完成,不关注是否全部执行成功,allSettled 状态只会是fulfilled。
下面的 p2 返回状态为 rejected ,但promise.allSettled 不关心,它始终将状态设置为 fulfilled 。
const p1 = new Promise((resolve, reject) => {
resolve("resolved");
});
const p2 = new Promise((resolve, reject) => {
reject("rejected");
});
Promise.allSettled([p1, p2])
.then(msg => {
console.log(msg);
})下面是获取用户信息,但不关注某个用户是否获取不成功
const api = "http://localhost:8888/php";
const promises = [
ajax(`${api}/user.php?name=1`),
ajax(`${api}/user.php?name=2`)
];
Promise.allSettled(promises).then(response => {
console.log(response);
});race
使用Promise.race() 处理容错异步,和race单词一样哪个 Promise 快用哪个,哪个先返回用哪个。
- 以最快返回的 promise 为准
- 如果最快返加的状态为
rejected那整个promise为rejected执行 cache - 如果参数不是 promise,内部将自动转为 promise
下面将第一次请求的异步时间调整为两秒,这时第二个先返回就用第二人。
const hdcms = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第一个Promise");
}, 2000);
});
const houdunren = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("第二个异步");
}, 1000);
});
Promise.race([hdcms, houdunren])
.then(results => {
console.log(results);
})
.catch(msg => {
console.log(msg);
});获取用户资料,如果两秒内没有结果 promise.race 状态失败,执行catch 方法
const api = "http://localhost:8888/php";
const promises = [
ajax(`${api}/user.php?name=2`),
new Promise((a, b) =>
setTimeout(() => b(new Error("request fail")), 2000)
)
];
Promise.race(promises)
.then(response => {
console.log(response);
})
.catch(error => {
console.log(error);
});任务队列
实现原理
如果 then 返回promise 时,后面的then 就是对返回的 promise 的处理
let promise = Promise.resolve();
let p1 = promise.then(() => {
return new Promise(resolve => {
setTimeout(() => {
console.log(`p1`);
resolve();
}, 1000);
});
});
p1.then(() => {
return new Promise((a, b) => {
setTimeout(() => {
console.log(`p2`);
}, 1000);
});
});下面使用 map 构建的队列,有以下几点需要说明
then内部返回的promise更改外部的promise变量- 为了让任务继承,执行完任务需要将
promise状态修改为fulfilled
function queue(nums) {
let promise = Promise.resolve();
nums.map(n => {
promise = promise.then(v => { //关键是将上一个promise的结果传递给下一个then
return new Promise(resolve => {
console.log(n);
resolve();
});
});
});
}
queue([1, 2, 3, 4, 5]);下面再来通过 reduce 来实现队列
function queue(nums) {
return nums.reduce((promise, n) => {
return promise.then(() => {//相当于map的复制操作
return new Promise(resolve => {
console.log(n);
resolve();
});
});
}, Promise.resolve());
}
queue([1, 2, 3, 4, 5]);队列请求
下面是异步加载用户并渲染到视图中的队列实例
- 请在后台添加延迟脚本,以观察队列执行过程
- 也可以在任何
promise中添加定时器观察
class User {
//加载用户
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 this.ajax(user);
})
.then(user => {
return this.view(user);
});
}, Promise.resolve());
}
//宣染视图
view(user) {
return new Promise(resolve => {
let h1 = document.createElement("h1");
h1.innerHTML = user.name;
document.body.appendChild(h1);
resolve();
});
}
}
new User().render(["向军", "后盾人"]);高可用封装
上例中处理是在队列中完成,不方便业务定制,下面将 Promise 处理在剥离到外部
后台请求处理类
export default function(url) {
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.send()
xhr.onload = function() {
if (this.status === 200) {
resolve(this.response)
} else {
reject(this)
}
}
})
}队列处理类
export default function(promises) {
promises.reduce((promise, next) => promise.then(next), Promise.resolve())
}async/await
使用 async/await 是 promise 的语法糖,可以让编写 promise 更清晰易懂,也是推荐编写 promise 的方式。
async/await本质还是 promise,只是更简洁的语法糖书写async/await使用更清晰的 promise 来替换 promise.then/catch 的方式
async == promise
下面在 hd 函数前加上 async,函数将返回 promise,我们就可以像使用标准 Promise 一样使用了。
async function hd() {
return "dd.com";
}
console.log(hd());
hd().then(value => {
console.log(value);
});如果有多个 await 需要排队执行完成,我们可以很方便的处理多个异步队列
async function hd(message) {
return new Promise(resolve => {
setTimeout(() => {
resolve(message);
}, 2000);
});
}
async function run() {
let h1 = await hd("dd");
console.log(h1);
let h2 = await hd("dd.com");
console.log(h2);
}
run();await == then
使用 await 关键词后会等待 promise 完
await后面一般是 promise,如果不是直接返回await必须放在 async 定义的函数中使用await用于替代then使编码更优雅
下例会在 await 这行暂停执行,直到等待 promise 返回结果后才继执行。
dasync function hd() {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("dd.com");
}, 2000);
});
let result = await promise;
console.log(result);
}
hd()一般 await 后面是外部其它的 promise 对象
async function hd() {
return new Promise(resolve => {
setTimeout(() => {
resolve("fulfilled");
}, 2000);
});
}
async function run() {
let value = await hd();
console.log("dd.com");
console.log(value);
}
run();也可以将操作放在立即执行函数中完成
(async () => {
let user = await ajax(`http://localhost:8888/php/user.php?name=44`);
let lessons = await ajax(
`http://localhost:8888/php/houdunren.php?id=${user.id}`
);
console.log(lessons);
})();下面是使用 async 设置定时器,并间隔时间来输出内容
async function sleep(ms = 2000) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
async function run() {
for (const value of ["dd", "ss"]) {
await sleep();
console.log(value);
}
}
run();async, await 先收到第一个请求,再继续第二个请求。
async function hd() {
let name = await new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第一次请求')
resolve('第一次请求')
}, 1000)
})
await new Promise((resolve, reject) => {
setTimeout(() => {
console.log('第二次请求')
resolve('第二次请求')
}, 1000)
})
}
hd()类中使用
和 promise 一样,await 也可以操作thenables 对象
class User {
constructor(name) {
this.name = name;
}
then(resolve, reject) {
let user = ajax(`http://localhost:8888/php/user.php?name=${this.name}`);
resolve(user);
}
}
async function get() {
let user = await new User("love");
console.log(user);
}
get();类方法也可以通过 async 与 await 来操作 promise
class User {
constructor() {}
async get(name) {
let user = await ajax(
`http://localhost:8888/php/user.php?name=${name}`
);
//等待异步方法执行完再可以继续执行
user.name += "-houdunren.com";
return user;
}
}
new User().get("love").then(resolve => {
console.log(resolve);
});其他声明
函数声明
async function get(name) {
return await ajax(`http://localhost:8888/php/user.php?name=${name}`);
}
get("love").then(user => {
console.log(user);
});函数表达式
let get = async function(name) {
return await ajax(`http://localhost:8888/php/user.php?name=${name}`);
};
get("love").then(user => {
console.log(user);
});对象方法声明
let hd = {
async get(name) {
return await ajax(`http://localhost:8888/php/user.php?name=${name}`);
}
};
hd.get("love").then(user => {
console.log(user);
});立即执行函数
(async () => {
let user = await ajax(`http://localhost:8888/php/user.php?name=love`);
let lessons = await ajax(
`http://localhost:8888/php/houdunren.php?id=${user.id}`
);
console.log(lessons);
})();类方法中的使用
class User {
async get(name) {
return await ajax(`http://localhost:8888/php/user.php?name=${name}`);
}
}
let user = new User().get("love").then(user => {
console.log(user);
});错误处理
async 内部发生的错误,会将必变 promise 对象为 rejected 状态,所以可以使用catch 来处理
async function hd() {
console.log(houdunren);
}
hd().catch(error => {
throw new Error(error);
});下面是异步请求数据不存在时的错误处理
async function get(name) {
return await ajax(`http://localhost:8888/php/user.php?name=${name}`);
}
get("love").catch(error => {
alert("用户不存在");
});如果promise 被拒绝将抛出异常,可以使用 try...catch 处理错误
async function get(name) {
try {
let user = await ajax(
`http://localhost:8888/php/user.php?name=${name}`
);
console.log(user);
} catch (error) {
alert("用户不存在");
}
}
get("lover");多个 await 时当前面的出现失败,后面的将不可以执行
async function hd() {
await Promise.reject("fail");
await Promise.resolve("success").then(value => {
console.log(value);
});
}
hd();如果对前一个错误进行了处理,后面的 await 可以继续执行
async function hd() {
await Promise.reject("fail").catch(e => console.log(e));
await Promise.resolve("success").then(value => {
console.log(value);
});
}
hd();也可以使用 try...catch 特性忽略不必要的错误
async function hd() {
try {
await Promise.reject("fail");
} catch (error) {}
await Promise.resolve("success").then(value => {
console.log(value);
});
}
hd();也可以将多个 await 放在 try...catch 中统一处理错误
async function hd(name) {
const host = "http://localhost:8888/php";
try {
const user = await ajax(`${host}/user.php?name=${name}`);
const lessons = await ajax(`${host}/user.php?id=${user.id}`);
console.log(lessons);
} catch (error) {
console.log("用户不存在");
}
}
hd("后盾人教程");并发执行
有时需要多个 await 同时执行,有以下几种方法处理,下面多个 await 将产生等待
async function p1() {
return new Promise(resolve => {
setTimeout(() => {
console.log("houdunren");
resolve();
}, 2000);
});
}
async function p2() {
return new Promise(resolve => {
setTimeout(() => {
console.log("hdcms");
resolve();
}, 2000);
});
}
async function hd() {
await p1();
await p2();
}
hd();使用 Promise.all() 处理多个 promise 并行执行
async function hd() {
await Promise.all([p1(), p2()]);
}
hd();让 promise 先执行后再使用 await 处理结果
async function hd() {
let h1 = p1();
let h2 = p2();
await h1;
await h2;
}
hd();