Node.js 12实战
上QQ阅读APP看书,第一时间看更新

2.5.1 同步和异步

首先,理解同步和异步的概念。同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,则这个进程将会一直等待下去,直到收到返回信息才继续执行下去;异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时,系统会通知进程进行处理,这样可以提高执行的效率。

由于JavaScript是单线程模型,执行IO操作时,JavaScript代码无须等待,而是传入回调函数后,继续执行后续的JavaScript代码。比如jQuery提供的getJSON()操作:

$.getJSON('http://example.com/ajax', function (data) {
    console.log('IO结果返回后执行...');
});
console.log('不等待IO结果直接执行后续代码...');

而同步的IO操作则需要等待函数返回:

// 根据网络耗时,函数将执行几十毫秒到几秒不等
var data = getJSONSync('http://example.com/ajax');

同步操作的好处是代码简单,缺点是程序将等待IO操作,在等待时间内,无法响应其他任何事件,而异步读取则不需要等待IO操作。

还可以使用async/await来处理异步。async函数返回一个Promise对象,可以使用then方法添加回调函数。当函数执行时,遇到await就会等待其异步操作完成,然后执行函数体后面的语句。async放在函数前,表示函数里有异步操作,例如:

async function foo(){
} //函数声明

或:

const foo = async function foo(){
} // 函数表达式

async函数的返回值为Promise对象:

async function f(){
  return 'hello world';
}
f().then(v => console.log(v));
// "hello world"
async function f(){
  throw new Error('报错了'); // 返回的Promise对象为reject状态
}
f().then(
  v => console.log(v),
  e => console.log(e)
);
// Error: 报错了
// 用catch接受错误信息
async function f(){
  throw new Error('报错了');
}
f()
.then(v => console.log(v))
.catch(e => console.log(e))
// Error: 报错了

await表示紧跟在后面的表达式需要等待结果。一般为Promise对象,如果不是,就会被转成一个立即resolve的Promise对象。

【示例2-4】防止异步函数出错,需要把await命令放在try…catch代码块中:

同步问题多发生在多线程环境的数据共享问题中,即当多个线程需要访问同一个资源时,它们需要以某种顺序来确保该资源在某一特定时刻只能被一个线程访问,如果使用异步,程序的运行结果将不可预料。因此,在这种情况下,就必须对数据进行同步,即限制只能有一个进程访问资源,其他线程必须等待。