yjjnls/Notes

View on GitHub
js/node/asynchronization.md

Summary

Maintainability
Test Coverage
# Asynchronization of node

## 难点

### 异常处理
**异步IO的实现主要分为两节阶段:提交请求和处理结果。这两个阶段中间是有其他时间循环的调度,两者彼此不关联。**  
异步方法通常在第一阶段提交请求后就会立即返回一个结果,但是真正的处理和结果返回在另一个阶段,这也是异常发生的地方。  
**try/catch只能捕获档次循环内的异常,当callback执行时抛出的异常无法捕捉。**

一般约定在回调函数callback中将第一个参数设err,如果err不为空,说明发生了异常。

### 函数嵌套过深

## 解决方案
### 事件发布/订阅模式
通过events模块中的信号来处理,提交异步处理时订阅相关信号,当处理完成时,处理模块发射相应信号。这样在之后的循环中,就会触发该信号的回调。


### 异步模式(async/await)

async 表示这是一个async函数,await只能用在这个函数里面

await 表示在这里等待promise返回结果了,再继续执行。

#### 获得返回值
await等待的虽然是promise对象,但不必写.then(..),直接可以得到返回值。
```js
var sleep = function (time) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            // 返回 ‘ok’
            resolve('ok');
        }, time);
    })
};

var start = async function () {
    let result = await sleep(3000);
    console.log(result); // 收到 ‘ok’
};
```

#### 捕捉错误
既然.then(..)不用写了,那么.catch(..)也不用写,可以直接用标准的try catch语法捕捉错误。
```js
var sleep = function (time) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            // 模拟出错了,返回 ‘error’
            reject('error');
        }, time);
    })
};

var start = async function () {
    try {
        console.log('start');
        await sleep(3000); // 这里得到了一个返回错误
        
        // 所以以下代码不会被执行了
        console.log('end');
    } catch (err) {
        console.log(err); // 这里捕捉到错误 `error`
    }
};
```

https://www.cnblogs.com/YikaJ/p/4996174.html 

Promise.then
Promise.catch
Promise.resolve
Promise.reject
Promise.all
Promise.race

https://promisesaplus.com/

## 发展历史
### callback
```js
mongoDb.open(function(err, db){
    if(!err){
        db.collection("users", function(err, collection){
            if(!err){
                let person = {name: "yika", age: 20};
                collection.insert(person, function(err, result){
                    if(!err){
                        console.log(result);
                    }
                });
            }
        })
    }
});
```
### promise
```js
let person = {name: "yika"};
mongoDb
    .open()
    .then(function(database){
      return database.collection("users");
    })
    .then(function(collection){
      return collection.insert(person);
    })
    .then(function(result){
      console.log(result);
    })
    .catch(function(e){
      throw new Error(e);
    })
```
promise是一个异步编程的抽象,它是一个返回值或抛出exception的代理对象  
* promise只有三种状态,未完成,完成(fulfilled)和失败(rejected)。  
* promise的状态可以由未完成转换成完成,或者未完成转换成失败。  
* promise的状态转换只发生一次  
promise有一个then方法,`then方法可以接受3个函数作为参数`。**前两个函数对应promise的两种状态fulfilled, rejected的回调函数。第三个函数用于处理进度信息。**

```js
var promise = readFile();
promise.then(console.log, console.error);
```
**`.then()总是返回一个新的promise.`**   
例如第一个例子中,mongoDb.open()可以看做一个promise,打开数据库这个异步操作成功后,调用第一个then,执行下一个异步操作`database.collection("users")`,然后这个then返回一个新的promise对象,该对象就表示执行`database.collection("users")`这个异步操作。

* important
如果某个then没有显示地return一个pormise,那么会默认return一个空的promise,并继续执行下面的then。**此时下一个then的回调中的res参数为空,否则应该是上一promise的resolve返回值。**

reject 是拒绝,跳转到catch error
resolve 是解决,下一步,即跳转到下一个promise操作

如果异步行为没有返回promise对象,那么就要自己再包一层,例如
```js
var sleep = function (time) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            // 返回 ‘ok’
            resolve('ok');
        }, time);
    })
};

var start = async function () {
    let result = await sleep(3000);
    console.log(result); // 收到 ‘ok’
};
```


### async/await
```js
async function insertData(person){
    let db, collection, result; 
    try{
        db = await mongoDb.open();
        collection = await db.collection("users");
        result = await collection.insert(person);
    }catch(e){
        console.error(e.message);
    }
    console.log(result);
} 

insertData({name: "yika"});
```