zoukankan      html  css  js  c++  java
  • node异步编程

    Node.js异步编程

    同步API,异步API

    同步API:只有当前API执行完成后,才能继续执行下一个API

    console.log('before');
    console.log('after');
    

    异步API:当前API的执行不会阻塞后续代码的执行

    console.log('before');
    setTimeout(
    	() => {console.log('last');
    },2000);
    console.log('after');
    

    区别

    • 同步API可以从返回值中拿到API执行的结果,但是异步API是不可以的
    • 同步API从上到下依次执行,前面代码会阻塞后面代码的执行;异步API不会等待API执行完后再向下执行代码(node不会从上到下依次执行代码,而是先将同步API执行完再去执行异步API)
    //同步
    function sum(n1,n2){
    	return n1 + n2;
    }
    const result = sum (10 , 20);
    
    //异步
    function getMsg(){
    	setTimeout(function(){
    		return { msg: 'Hello Node.js'}
    	},2000);
    	//return undefined;
    }
    const msg = getMsg();
    console.log(msg);		//undefined,异步不会阻塞后面代码的运行
    

    那么要怎么取到异步API的返回值呢?

    回调函数

    自己定义函数让别人去调用

    //getData函数定义
    function getData(callback){}
    //getData函数调用
    getData (() => {});
    
    function getMsg(){
    	setTimeout(function(){
    		callback({
    			msg: 'Hello Node.js'
    		})
    	},2000)
    }
    getMsg((data) => {
    	console.log(data);
    })
    //异步API不能通过return获取到返回结果,而是需要通过回调函数来获取
    

    如果异步API后面的执行依赖当前异步API 的执行结果,但实际上后续代码在执行的时候异步API还没有返回结果,这个问题要怎么解决呢?

    假如需要依次读取三个文件A,B,C

    fs.readFile('./1.txt',(err,res1)=>{
    	console.log(res1)
    	fs.readFile('./2.txt',(err,res2)=>{
    		console.log(res2)
    		fs.readFile('./3.txt',(err,res3)=>{
    			console.log(res3)
    		})
    	})
    })
    

    功能实现了但是不利于阅读和维护,写出回调地狱

    回调地狱根本问题是:

    1. 嵌套函数存在耦合性,一旦有所改动,就会牵一发而动全身
    2. 嵌套函数多了就很难处理错误

    Promise

    Promise出现的目的是解决Node.js异步编程中回调地狱的问题。

    let promise = new Promise((resolve, reject) => {
        //resolve将异步的结果通过参数的形式传递出去
        //reject将失败的结果传递出去
      setTimeout(() => {
        if (true) {
          resolve({ name: "张三" });
        } else {
          reject("失败了");
        }
      }, 2000);
    });
    promise
      .then((result) => console.log(result))
      .catch((error) => console.log(error));
    
    

    示例:

    const fs = require("fs");
    let promise = new Promise((resolve, reject) => {
      fs.readFile("./1.txt", "utf8", (error, result) => {
        if (error != null) {
          reject(error);
        } else {
          resolve(result);
        }
      });
    });
    promise
      .then((result) => console.log(result))
      .catch((error) => console.log(error));
    
    

    解决上述回调地狱问题:

    const fs = require("fs");
    function p1() {
      return new Promise((resolve, reject) => {
        fs.readFile("./1.txt", "utf8", (error, result) => {
          resolve(result);
        });
      });
    }
    function p2() {
      return new Promise((resolve, reject) => {
        fs.readFile("./2.txt", "utf8", (error, result) => {
          resolve(result);
        });
      });
    }
    function p3() {
      return new Promise((resolve, reject) => {
        fs.readFile("./3.txt", "utf8", (error, result) => {
          resolve(result);
        });
      });
    }
    p1()
      .then((r1) => {
        console.log(r1);
        return p2();
      })
      .then((r2) => {
        console.log(r2);
        return p3();
      })
      .then((r3) => {
        console.log(r3);
      });
    
    

    异步函数

    异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了。

    const fn = async () => {};
    
    async function fn(){}
    
    async function fn(){
    	throw '出错了';
    	return 123;
    }
    fn().then(data => console.log(data))
    	.catch(err => console.log(err))
    
    async function p1(){
    	return 'p1';
    }
    async function p2(){
    	return 'p2';
    }
    async function p3(){
    	return 'p3';
    }
    async function run(){
    	let r1 = await p1()
    	let r2 = await p2()
    	let r3 = await p3()
    	console.log(r1)
    	console.log(r2)
    	console.log(r3)
    }
    run();
    
    async关键字
    1. 普通函数定义前加async关键字,普通函数变成异步函数
    2. 异步函数默认返回promise对象
    3. 在异步函数内部使用return关键字进行结果返回,结果会被包裹在promise对象中,return关键字代替了resolve方法
    4. 在异步函数内部使用throw关键字抛出程序异常
    5. 调用异步函数再链式调用then方法获取异步函数执行结果
    6. 调用异步函数再链式调用catch方法获取异步函数执行的错误信息
    await关键字
    1. await关键字只能出现在异步函数中
    2. await promise await后面只能写promise对象,写其他类型的API是不可以的
    3. await关键字可暂停异步函数向下执行,直到promise返回结果

    解决回调地狱,读取文件方法

    const fs = require("fs");
    //改造现有异步函数api,让其返回promise对象,从而支持异步函数语法
    const promisify = require("util").promisify;
    //调用promisify方法改造现有异步API,让其返回promise对象
    const readFile = promisify(fs.readFile);
    async function run() {
      let r1 = await readFile("./1.txt", "utf8");
      let r2 = await readFile("./2.txt", "utf8");
      let r3 = await readFile("./3.txt", "utf8");
      console.log(r1);
      console.log(r2);
      console.log(r3);
    }
    run();
    
  • 相关阅读:
    [Web] 网络安全(SSH SSL HTTPS)
    [OS] 操作系统课程(三)
    [刷题] 203 Remove Linked List Elements
    [刷题] 206 Reverse Linked List
    for循环中let与var的区别,块级作用域如何产生与迭代中变量i如何记忆上一步的猜想
    es6入门1-- let与var的区别详解
    精读JavaScript模式(八),JS类式继承与现代继承模式其一
    精读JavaScript模式(七),命名空间模式,私有成员与静态成员
    精读JavaScript模式(六),Memoization模式与函数柯里化的应用
    精读JavaScript模式(五),函数的回调、闭包与重写模式
  • 原文地址:https://www.cnblogs.com/actorhuang/p/13766720.html
Copyright © 2011-2022 走看看