异步编程
1 同步API、异步API
- 同步API:只有当前API执行完毕,才能接着执行下面的API。
console.log('hello');
console.log(' world');
//hello world
- 异步API:当前API的执行不会影响和阻塞后续API的执行。
setTimeout(()=>{
console.log('hello');
},3000);
console.log('world');
// worldhelllo
2 二者区别
- 获取返回值。同步API可以从返回值拿到API结果,异步不可以。
- 回调函数。
- 代码执行顺序。
- 同步API从上到下依次执行,会阻塞后面的代码执行;
- 异步API异步执行,不会阻塞后面的代码执行。
3 node.js异步API
fs.readFile()
var serve = http.createHttp();
- 回调地狱:回调嵌套回调,回调再嵌套回调…。
- Promise可以解决回调地狱问题。
Promise
1 定义
Promise本身是一个构造函数,其存在的意义就是为了解决node.js异步编程中回调地狱的问题。
const promise = new Promise((resolve,reject)=>{
//异步API写在内部
if(true){
//调用resolve函数,向外传递API执行结果。实际上就是执行promise.then()这个函数
resolve('执行成功');
}else{
reject('执行失败');
}
})
//接收API结果 promise允许链式编程
promise.then((result)=>{
console.log(result); //执行成功
})
.catch((err)=>{
console.log(err);
});
- resolve():将异步API的执行结果传递出去。
- promise.then():接收resolve()传递的参数。
- reject():本身也是函数,当异步执行失败,把失败结果传递到promise外面。
- promise.catch():接收reject()传递的参数。
//解决回调地狱
const fs = require('fs');
function fn1 () {
//返回promise对象
return new Promise((resolve,reject) => {
fs.readFile('./1.txt','utf-8',(err,result) => {
resolve(result);
});
})
}
function fn2 () {
return new Promise((resolve,reject) => {
fs.readFile('./2.txt','utf-8',(err,result) => {
resolve(result);
});
})
}
function fn3 () {
return new Promise((resolve,reject) => {
fs.readFile('./3.txt','utf-8',(err,result) => {
resolve(result);
});
})
}
//promise链式编程 输出API返回值
//输出函数fn1的值,返回函数fn2的调用(Promise对象)
fn1().then((r1) => {
console.log(r1);
return fn2();
})
//输出函数fn2的值,返回函数fn3的调用(Promise对象)
.then((r2) => {
console.log(r2);
return fn3();
})
//输出函数fn3的值
.then((r3) => {
console.log(r3);
});
异步函数
可以把异步代码写成同步代码的形式,代码不再有回调函数嵌套,更清晰。
1 async关键字
- 普通函数定义的前面加上async关键字。
- 异步函数默认的返回值是promise对象。
- 在异步函数内使用return关键字代替resolve,进行结果返回,结果被包裹在promise对象中。
- 在异步函数内使用throw关键字抛出错误信息。
- 调用异步函数,再链式调用then方法获取异步函数执行结果。
- 调用异步函数,再链式调用catch方法获取异步函数执行的错误信息。
2 await关键字
- 只能出现在异步函数内。
- await promise后面只能写promise对象。
- await promise可以暂停异步函数的向下执行,直到promise对象返回结果。
async function fn(){
//throw抛出错误(后面代码不在执行)
throw '发生错误';
//用return代替resolve将执行结果传递出去
return 132;
};
fn().then((data)=>{
console.log(data);
})
.catch((err)=>{
console.log(err);
});
async function fn1(){
return 'f1';
}
async function fn2(){
return 'f2';
}
async function fn3(){
return 'f3';
}
async function run() {
console.log(await fn1());
console.log(await fn2());
console.log(await fn3());
}
run(); //f1 f2 f3
改造现有异步函数API
const fs = require('fs');
//改造异步函数API,令其返回promise对象,从而支持异步函数语法
const promisify = require('util').promisify;
//调用promisify方法改造现有异步API,返回promise对象
const readFile = promisify(fs.readFile);
async function run() {
console.log(await readFile('./a.txt','utf-8'));
console.log(await readFile('./a.txt','utf-8'));
console.log(await readFile('./a.txt','utf-8'));
}
run();