NodeJS中如何处理好异步API

简介: NodeJS中如何处理好异步API

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


参考资料 阮一峰 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


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



相关文章
|
10月前
|
缓存 边缘计算 监控
89_批量推理:异步API调用
在当今数据密集型应用和大模型部署的时代,批量推理已成为提升系统性能和资源利用率的关键技术。随着深度学习模型规模的不断扩大和应用场景的日益复杂,如何高效地处理大量推理请求成为技术团队面临的重要挑战。传统的同步API调用方式在面对高并发、大规模数据处理时,往往会遇到响应延迟高、资源利用不充分等问题。异步API调用作为一种更高效的处理模式,通过非阻塞操作和并发处理能力,为批量推理场景提供了理想的解决方案。
695 0
|
JavaScript 前端开发 API
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
API C#
异步轮询 Web API 的实现与 C# 示例
异步轮询 Web API 的实现与 C# 示例
577 1
|
存储 前端开发 JavaScript
node中循环异步的问题[‘解决方案‘]_源于map循环和for循环对异步事件配合async、await的支持
本文探讨了在Node.js中处理循环异步操作的问题,比较了使用map和for循环结合async/await处理异步事件的差异,并提供了解决方案。
267 0
|
存储 JavaScript API
Node.js中的异步API
【8月更文挑战第16天】
249 1
|
数据采集 JavaScript 前端开发
NodeJS技巧:在循环中管理异步函数的执行次数
在Node.js网络爬虫开发中,管理异步函数执行次数是关键。利用Promise.all、async/await或async库能优雅地控制并发。示例展示如何用async/await配合代理IP抓取数据,避免触发反爬策略。在循环中,每个异步请求只执行一次,保证请求有序进行,提高爬虫的稳定性和效率。通过正确的方法,可以有效应对网络爬虫的挑战。
295 7
NodeJS技巧:在循环中管理异步函数的执行次数
|
前端开发 小程序 API
【微信小程序】使用 Promise、async 和 await 将异步API 改写为同步
【微信小程序】使用 Promise、async 和 await 将异步API 改写为同步
792 0
|
缓存 前端开发 JavaScript
中间件异步API
【6月更文挑战第18天】
202 3
|
JavaScript 大数据 开发者
Node.js的异步I/O模型与事件循环:深度解析
【4月更文挑战第29天】本文深入解析Node.js的异步I/O模型和事件循环机制。Node.js采用单线程与异步I/O,遇到I/O操作时立即返回并继续执行,结果存入回调函数队列。事件循环不断检查并处理I/O事件,通过回调函数通知结果,实现非阻塞和高并发。这种事件驱动编程模型简化了编程,使开发者更专注业务逻辑,为高并发场景提供高效解决方案。