NodeJS中如何处理好异步API

2,098 阅读2分钟

异步编程 - 如何控制好异步过程

参考资料 阮一峰 Javascript异步编程的4种方法)

  • JS的执行环境是单线程(Single thread)

  • I/O处理需要回调函数异步处理 (异步I/O)

  • 前端异步IO可以消除UI阻塞,提高用户体验

  • 而放在后端则可以提高CPU和内存里利用率

串联异步处理

异步操作队列化,按照期望的顺序执行。

Callback

回调地域太可怕

const logTime = (name) => {
    console.log(`Log....${name}   ` + new Date().toLocaleTimeString())
}

exports.callback = () => {
    setTimeout(() => {
        logTime('callback 1')
        setTimeout(() => {
            logTime('callback 2')
        }, 100)
    }, 100)
}

测试代码

test('callback', done => {
  callback()
  // 延时4s结束
  setTimeout(done, 1000)
})

Promise

The Promise object is used for asynchronous computations. A Promise represents a single asynchronous operation that hasn't completed yet, but is expected in the future.

译文:Promise对象用于异步操作,它表示一个尚未完成且预计在未来完成的异步操作。

说白了就是一个异步执行的状态机,异步执行的承诺。

const promise = (name, delay = 100) => new Promise(resolve => {
    setTimeout(() => {
        logTime(name)
        resolve()
    }, delay)
})

exports.promise = () => {

    promise('Promise1')
        .then(promise('Promise2'))
        .then(promise('Promise3'))
        .then(promise('Promise4'))
}

Gennerator

ES6 新引入了 Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。 基本

  • function -> function* 称为Gennerator函数
  • 函数内部有 yield 表达式。
function* func() {
    console.log("one");
    yield '1';
    console.log("two");
    yield '2';
    console.log("three");
    return '3';
}

const f = func()
f.next();
// one
// {value: "1", done: false}
f.next();
// two
// {value: "2", done: false}
f.next();
// three
// {value: "3", done: true}
f.next();
// {value: undefined, done: true}

// 或者通过迭代器
for (const [key,value] of func()) {
    console.log(`${key}: ${value}`);
}

逻辑代码
let co = function (gen, name) {
    var it = gen(name)
    var ret = it.next()
    ret.value.then(function (res) {
        it.next(res)
    })
}
exports.generator = () => {
    const generator = function* (name) {
        yield promise(name + 1)
        yield promise(name + 2)
        yield promise(name + 3)
        yield promise(name + 4)
    }
    let co = generator => {
        if (it = generator.next().value) {
            it.then(res => {
                co(generator)
            })
        } else {
            return
        }
    }
    co(generator('Co-Generator'))
}

async/await

async/await是es7推出的一套关于异步的终极解决方案

  • 任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。
  • async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作执行完,才会执行then方法指定的回调函数。
exports.asyncAwait = async () => {
    await promise('Async/Await1')
    await promise('Async/Await2')
    await promise('Async/Await3')
    await promise('Async/Await4')
}

事件监听方式处理

采用事件驱动模式。任务的执行不取决于代码的顺序,而取决于某个事件是否发生。

exports.event = async () => {
    const asyncFun = name => event => {
        setTimeout(() => {
            logTime(name)
            event.emit('end')
        }, 100)
        return event
    }

    const ary = [
        asyncFun('event1'),
        asyncFun('event2'),
        asyncFun('event3')
    ]

    const { EventEmitter } = require('events')
    const event = new EventEmitter()
    let i = 0
    event.on('end', () => i < ary.length && ary[i++](event))
    event.emit('end')

}

eventEmmiter

const promise = (name, delay = 100) => new Promise(resolve => {
    setTimeout(() => {
        logTime(name)
        resolve()
    }, delay)
})

exports.promise = () => {

    promise('Promise1')
        .then(promise('Promise2'))
        .then(promise('Promise3'))
        .then(promise('Promise4'))
}

扩展阅读eventEimitter源码解析 / 订阅发布机制

class EventEmitter {
    constructor() {
        this.handler = {};
    }
    on(eventName, callback) {
        if (!this.handles) {
            this.handles = {};
        }
        if (!this.handles[eventName]) {
            this.handles[eventName] = [];
        }
        this.handles[eventName].push(callback);
    }
    emit(eventName, ...arg) {
        if (this.handles[eventName]) {
            for (var i = 0; i < this.handles[eventName].length; i++) {
                this.handles[eventName][i](...arg);
            }
        }

    }
}

const event = new EventEmitter(); 
event.on('some_event', num =>  { 
    console.log('some_event 事件触发:'+num); 
}); 
let num = 0
setInterval(() =>  { 
    event.emit('some_event' , num ++ ); 
}, 1000); 

RxJS

对于事件流的控制 -- 近期推出 --