zoukankan      html  css  js  c++  java
  • 异步代码

    一、Promise

      promise表示一个异步操作的最终结果,可以理解为状态机,它存在三种不同的状态:

    (1)Pending:表示还在执行。

    (2)Fulfilled(或者resolved):执行成功。

    (3)Rejected:执行失败。

    1、将异步方法封装成Promise

     1 //Promise的构造函数
     2 var promise = new Promise(function (resolve,reject) {
     3     if(/*异步操作成功*/){
     4         resolve(value);
     5     }else{
     6         reject(value);
     7     }
     8 })
     9 //使用Promise封装的readFile
    10 var fs = require("fs");
    11 function readFile_promise(path) {
    12     return new Promise(function(resolve, reject) {
    13         fs.readFile(path, "utf-8", function(err, data) {
    14             if (data) {
    15                 resolve(data);
    16             } else {
    17                 reject(err);
    18             }
    19         });
    20     });
    21 }

    其中,resolve和reject是两个函数,resolve函数会在异步操作成功完成时被调用,并将异步操作的返回值作为参数传递到外部;reject则在异步操作出现异常时被调用,会将错误信息作为参数传递出去。即resolve和reject方法没有做多余的操作,仅仅把异步的结果传递出去而已,对于异步结果,是交给then方法来完成的。

    2、使用then方法获取结果

     1 //处理结构
     2 promise.then(function (data) {
     3     //success
     4 },function (error) {
     5     //failure
     6 })
     7 var pro = readFile_promise('foo.txt');
     8 pro.then(function(value) {
     9     console.log(value);
    10     return readFile_promise('bar.txt');
    11 }).then(function(value) {
    12     console.log(value);
    13 }).catch(function(err) {
    14     console.log(err);
    15 });//捕获异常

    3、Promise的常用API

    (1)Promise.resolve:将一个给Promise对象转化为Promise对象。但resolve不能转换一个异步方法,例如readFile方法。

     1 var obj = {
     2     then: function() {
     3         console.log("I am a then method");
     4     }
     5 }
     6 Promise.resolve(obj); //转化后的Promise会自动执行其的then方法
     7 //I am a then method
     8 var p = Promise.resolve("Hello World");
     9 p.then(function (result) {
    10     console.log(result);
    11 }); //Hello World

    (2)Promise.reject:也是返回一个Promise对象,不同之处在于这个Promise的状态为reject,reject方法的参数会作为错误信息传递给then方法。

    (3)Promise.all:将多个Promise对象包装成一个Promise。当调用Promise.all时,所有的Promise都已经开始执行了,all方法只是等到全部的Promise完成后,对所有的执行结果做一下包装再返回。

    1 var promises = ["foo.txt", "bar.txt", "baz.txt"].map(function(path) {
    2     return readFile_promise(path);
    3 });
    4 Promise.all(promises).then(function(results) {
    5     console.log(results); //results的内容是文本文件内容的顺序排列
    6 }).catch(function(err) {
    7 
    8 });

     (4)Promise.race:接收一个Promise数组作为参数并返回一个新的Promise,数组中的Promise会同时开始执行,race返回的Promise的状态由数组中率先执行完毕的Promise的状态决定。

    (5)Promise.catch:Promise在执行中如果出了错误,可以使用throw关键字抛出错误,并且可以使用catch方法进行去捕获;如果不设置任何回调函数捕获错误,Promise内部抛出的错误就无法传递到外部。

    1 var promise = new Promise(function(resolve, reject) {
    2     throw new Error("get error");
    3 });
    4 //如果不设置catch函数,上面即使抛出error也不会使进程退出。
    5 promise.catch(function(error) {
    6     console.log(error);
    7 });

    4、Promise的不足:Promise的一堆链式调用会让人看起来很麻烦。可以考虑将then方法的回调函数抽取出来。

    二、Generator

      我们无法控制Promise的执行,新建一个Promise后,其状态自动转化为pending,同时开始执行,直到状态改变后我们才能进行下一步操作。而Generator函数不同,Generator函数可以由用户执行中断或者恢复执行的操作,Generator中断后可以转去执行别的操作,然后再回头从中断的地方恢复执行。

      Generator函数和普通函数在外表上最大的区别有两个:

    (1)在function关键字和方法名中间有个星号(*)。

    (2)方法体中使用“yield”关键字。

     1 var fs = require("fs");
     2 
     3 function readFile_promise(path) {
     4     return new Promise(function(resolve, reject) {
     5         fs.readFile(path, "utf-8", function(err, data) {
     6             if (data) {
     7                 resolve(data);
     8             } else {
     9                 reject(err);
    10             }
    11         });
    12     });
    13 }
    14 
    15 function* gen() {
    16     var result = yield readFile_promise('../baz.txt');
    17     console.log(result);
    18 }
    19 var g = gen();
    20 var result = g.next();
    21 //console.log(result);
    22 result.value.then(function(data) {
    23     g.next(data);
    24 });

    之所以可以使用Generator函数来处理异步任务,原因有二:

    (1)Generator函数可以中断和恢复执行,这个特性有yield关键字来实现。

    (2)Generator函数内外可以交换数据,这个特性由next函数来实现。

    即Generator函数处理异步任务的核心思想:先将函数暂停在某处,然后拿到异步操作的结果,然后再把这个结果传到方法体内。

    三、async

      async函数可以看作是自带执行器的Generator函数。await关键字后面往往是一个Promise,如果不是就隐式调用Promise.resolve来转换成一个Promise。

     1 var fs = require("fs");
     2 async function asyncFunc() {
     3 
     4     return "hello node";
     5 }
     6 asyncFunc().then(function(data) {
     7     console.log(data);
     8 });
     9 
    10 function readFile_promise(path) {
    11     return new Promise(function(resolve, reject) {
    12         fs.readFile(path, "utf-8", function(err, data) {
    13             if (data) {
    14                 resolve(data);
    15             } else {
    16                 reject(err);
    17             }
    18         });
    19     });
    20 }
    21 
    22 aysnc
    23 
    24 function readFile() {
    25     var result = await readFile_promise("../foo.txt");
    26     console.log('test');
    27 }
    28 readFile();

      async函数的优点:可以实现自动执行,无须借助第三方模块等,也免去了Generator函数中一些复杂的概念,async函数的声明和执行与普通同步函数几乎一模一样(除了async和await关键字外)。

      async函数也有一些不足的地方,如果我们有很多层的方法调用,最底层的异步操作被封装成了async方法,那么该函数的所有上层方法可能都要变成async方法。

     

     

      

  • 相关阅读:
    2020牛客多校第十场C-Decrement on the Tree
    2020牛客多校第九场B- Groundhog and Apple Tree
    2020牛客多校第九场J-The Escape Plan of Groundhog
    2020牛客多校第九场E-Groundhog Chasing Death
    2020牛客多校第八场E-Enigmatic Partition
    2020牛客多校第八场A-All Star Game
    2020牛客多校第八场I-Interseting Computer Game
    2020牛客多校第七场H-Dividing
    2020牛客多校第七场J-Pointer Analysis
    2020牛客多校第七场C-A National Pandemic
  • 原文地址:https://www.cnblogs.com/daheiylx/p/9776531.html
Copyright © 2011-2022 走看看