首先,为什么要使用异步?
我在一篇文章中看到这样的说法:
在JavaScript的世界中,所有代码都是单线程执行的。由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。
说的更详细点,为什么单线程就需要异步呢?比如执行下面三个函数:
fun1();
fun2();
fun3();
如果三个函数执行速度都很快,单线程也没关系,顺序执行就是了。问题是,fun2()可能很耗时,这时fun3就需要等在那里,等fun2()返回了再执行。
fun3不想等怎么办呢?将fun2()改为异步函数,可以解决阻塞的问题。但如果fun3()依赖fun2的返回结果呢?有多重解决方案,所以你看,异步让fun3有了选择的权利,可以等待也可以不等待,而同步的话,fun3只能傻等。
什么是Promise?
Promise是ES6的语法,Promise作为一个构造函数,可以生成一个Promise实例,一般这么用:
const promise = new Promise(function (resolve, reject) {
// ... some code
if (/* 异步操作成功 */) {
resolve(value);
} else {
reject(error);
}
});
Promise的优点?
可以将“回调地狱”的写法改为工整的“.then”写法,MDN举了一个点餐的例子:
//改良前
chooseToppings(function (toppings) {
placeOrder(toppings, function (order) {
collectOrder(order, function (pizza) {
eatPizza(pizza);
}, failureCallback);
}, failureCallback);
}, failureCallback);
//改良后
chooseToppings()
.then(toppings => placeOrder(toppings))
.then(order => collectOrder(order))
.then(pizza => eatPizza(pizza))
.catch(failureCallback);
我的例子
Promise一般用于Web API的调用中,我试着举个例子,模拟一下(不一定准确):
// server
async function readTest() {
let a = 123;
return a;
}
// client interface
function apiTest() {
let data = readTest();
return data;
}
// main
function getA() {
let result = apiTest();
console.log(result);
}
getA();
sever是一个web服务,返回一个Promise;client interface是一个包装的、与服务端交互的接口;main调用这个接口,拿到服务结果123,并打印出来。
在node环境下执行这段代码,你会发现打印的是一个Promise对象,而非123,因为data是个Promise对象。将client interface改为下面的样子:
function apiTest() {
readTest().then((x) => {
return x;
});
}
x是123了,但getA()并没有拿到123,即没有等待getA()返回结果。
下面Promise对象登场,这样就可以正确打印了:
// server
async function readTest() {
let a = 123;
return a;
}
// client interface
function apiTest() {
return new Promise((resolve, reject) => {
let data = readTest();
resolve(data);
});
}
// main
function getA() {
const promise = apiTest();
promise.then((result) => {
console.log(result);
});
}
getA();
ES 2017引入了async/await的写法:
// server
async function readTest() {
let a = 123;
return a;
}
// client interface
async function apiTest() {
let data = await readTest();
return data;
}
// main
async function getA() {
let result = await apiTest();
console.log(result);
}
getA();