ES7引入的async/await在JavaScript异步编程中是一个很好的改进,它提供了使用同步样式的代码异步访问resources资源的方式,而且不会阻塞线程。
async函数返回的是一个Promise对象,async函数包括函数语句、函数表达式、Lambda表达式。
async函数会返回一个Promise对象,如果在async函数中return一个直接量,async会将这个直接量通过Promise.resolve()封装成Promise对象。
async function fn(){
return 1;
}
console.log(fn());//Promise {: 1}
async函数调用时会返回Promise对象,Promise对象拥有status和value。如果async函数拥有返回值,当调用async函数时,函数内部会调用Promise.resolve()方法将其转化为一个Promise对象并作为返回。
如果async函数没有返回值,则会返回Promise.resolve(undefined)。
async function fn(){
}
console.log(fn());//Promise {: undefined}
async函数调用时函数内部如果抛出错误则出现错误
async function fn(){
throw new Error("rejected");
}
console.log(fn());
在函数前添加async关键字后意味着函数将返回一个Promise,JavaScript编译器会自动函数返回值转换为一个Promise。
async function fn(){
return 1;
}
fn().then(alert);//1
function fn(){
return Promise.resolve(1);
}
fn().then(alert);//1
fn().then(console.log);//1
如果要获取async函数的执行结果,需要调用Promise对象的then或catch来为其注册回调函数。
async function fn(){
return 1;
}
fn().then(result=>console.log(result));//1
如果async函数执行完毕返回的Promise对象没有注册回调函数,比如函数内部做了一次for循环此时函数的调用就只是执行了函数体,这和普通的函数并没有区别。唯一的不同之处在于函数体执行完毕后返回的是一个Promise对象。
async function fn(){
for(let i=0; i<10; i++){
console.log("async fn:", i);
}
}
console.log(fn());
async函数的执行会返回一个Promise对象,并将内部的值进行promise封装,如果Promise对象通过then或catch方法注册了回调函数,async函数执行完毕后,注册的回调函数会放入到异步队列中等待执行。如果只是async函数则和promise一样,但有了await之后就不一样的,await关键字只能放到async函数中,await等待的是什么呢?
await等待的是一个表达式,这个表达式的计算结果是Promise对象或其他值,换句话说await可以等待任意表达式的结果。如果await等到的不是一个Promise对象,那么await表达式的运算结果就是它等到的东西。如果await等到的是一个Promise对象,await就会阻塞后续代码,等到Promise对象resolve,然后得到resolve的值作为await表达式的运算结果。
这也就是await必须用在async函数中的原因,async函数调用不会造成阻塞,async函数内部所有的阻塞都被封装在一个Promise对象中异步执行。
let result = await promise;
await的意思是让JavaScript编译器等待Promise结束,然后再输出结果。这里并不会占用CPU资源,因为JavaScript引擎可以同时执行其它任务或脚本或处理事件。
async function fn(){
let promise = new Promise((resolve, reject)=>{
setTimeout(()=>resolve("done"), 1000);
});
let result = await promise;//wait till the promise resolve
console.log(result);//done
}
fn();
fn函数执行时会在let result = await promise
位置暂停,直到Promise返回结果,因此代码会在1秒后在控制台输出done。
await不能单独使用,必须在async函数的作用域下使用,否则将会报异常Error:await is only valid in async function
。
function fn(){
let promise = new Promise((resolve, reject)=>{
setTimeout(()=>resolve("done"), 1000);
});
let result = await promise;//Uncaught SyntaxError: await is only valid in async function
console.log(result);
}
fn();
例如:摇色子等待3秒后得到最终的结果
function fn(){
let val = parseInt(Math.random() * 6 + 1);
let promise = new Promise((resolve, reject)=>{
setTimeout(()=>resolve(val), 3000);
});
return promise;
}
async function main(){
let val = await fn();
console.log(val);
}
main();
例如:摇色子猜大猜小,成功与失败的处理。
function fn(type){
return new Promise((resolve, reject)=>{
let val = parseInt(Math.random() * 6 + 1);
if(val > 3){
if(type === "big"){
resolve(val);
}else{
reject(val);
}
}else{
if(type === "big"){
reject(val);
}else{
resolve(val);
}
}
setTimeout(()=>resolve(val), 3000);
});
}
async function main(){
try{
let val = await fn("big");
console.log("win:", val);
}catch(error){
console.error("fail:", error);
}
}
main();
例如:有两个色子都买大,猜成功则返回两个的值,猜失败则返回第一个失败的结果。
function fn(type){
return new Promise((resolve, reject)=>{
let val = parseInt(Math.random() * 6 + 1);
if(val > 3){
if(type === "big"){
resolve(val);
}else{
reject(val);
}
}else{
if(type === "big"){
reject(val);
}else{
resolve(val);
}
}
setTimeout(()=>resolve(val), 3000);
});
}
Promise.all([fn("big"), fn("big")]).then(
(val)=>console.log("resolve:", val),
(val)=>console.log("reject:",val)
);
例如:话费充值,当用户输入电话号码后先查找电话号码所在的省市,在根据省市找到可能的重置面额。
创建项目安装依赖
$ mkdir charge && cd charge
$ npm init
$ npm i --save express
$ npm i --save body-parse
$ npm i -g supervisor
创建服务器
$ vim index.js
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(express.static("public"));
app.use(bodyParser.json());
app.post("/location", (req, res, next)=>{
const phone = req.body.phone;
setTimeout(()=>{
res.json({error:false, code:200, message:"success", result:{province:"湖南", city:"长沙"}});
}, 1000);
});
app.post("/facelist", (req, res, next)=>{
const province = req.body.province;
const city = req.body.city;
setTimeout(()=>{
res.json({error:false, code:200, message:"success", result:["20元", "30元", "50元"]});
}, 1000);
});
app.listen(3000, ()=>console.log("server start"));
创建视图界面
$ vim /public/index.html
Document
手机话费充值
所属地区
访问页面 http://127.0.0.1:3000