美文网首页
理解ES6的异步方案Promise/Generator/asyn

理解ES6的异步方案Promise/Generator/asyn

作者: 哎嘿沁 | 来源:发表于2017-09-06 21:23 被阅读0次

    异步

    • 不连续的执行,就叫做异步。相应地,连续的执行就叫做同步。
    • 通常异步是处理一些耗时的操作。

    回想在ES6没出现之前,需要异步处理事件的时候大多数情况下就是回调函数,可能还是是一层一层的callback嵌套,代码混乱逻辑不清晰,如果还有错误处理,那代码就更加冗杂让人不想去读第二遍!

    回调

    通过函数参数传递到其他代码里的,某一块可以执行的引用。

    容易引发的问题

    1.信任问题
    2.同步or异步 不确定?

    Promise对象

    所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

    • Promise 是一个对象,从它可以获取异步操作的消息。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
    构建Promise对象
    var promise = new Promise(function(resolve, reject) {
      // ... some code
      if (/* 异步操作成功 */){
        resolve(value);
      } 
      else {
        reject(error);
      }
    });
    

    promise的构造函数传入一个回调,该回调接受两个回调函数resolve和reject。
    resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

    Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。

    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    });
    

    Promise 提供then方法加载回调函数,catch方法捕捉执行过程中抛出的错误。

    Promise.resovle方法,可以将不是Promise对象作为参数,返回一个Promise对象。
    有两种情形:
    1.假设传入的参数没有一个.then方法,那么这个返回的Promise对象变成了resolve状态,其resolve的值就是这个对象本身。
    2.假设传入的参数带有一个then方法(称为thenable对象), 那么将这个对象的类型变为Promise,其then方法变成Promise.prototype.then方法。

    不管是then还是catch方法调用,都返回一个新的promise对象;其实then方法的调用,只不过是注册了完成态和失败态下的回调函数而已。这些回调函数组成一个回调队列,处理resolve的值。

    Q 链式调用的then和非链式调用的有什么区别?
    var promise1 = new Promise(function(resolve){
        resolve(1);
    });
    var thenPromise = promise1.then(function(value){
        console.log(value);
    });
    var catchPromise = thenPromise.catch(function(error){
        console.log(error);
    });
    console.log(promise1 !== thenPromise); // true
    console.log(thenPromise !== catchPromise); //true
    

    情况1

    var promise1 = new Promise(function(resolve){
        resolve(1);
    });
    promise1.then(function(value){
        return value * 2;
    });
    promise1.then(function(value){
        return value * 2;
    });
    promise1.then(function(value){
        console.log("1"+value);
    });
    

    情况2

    var promise1 = new Promise(function(resolve){
        resolve(2);
    });
    promise1.then(function(value){
        return value * 2;
    }).then(function(value){
        return value * 2;
    }).then(function(value){
        console.log("1"+value);
    });
    

    Generator 函数

    整个 Generator 函数就是一个异步任务的容器。

    Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。

    • Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态。

    • 调用 Generator 函数,返回一个遍历器对象,代表 Generator 函数的内部指针。每次调用遍历器对象的next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止,会返回一个有着value和done两个属性的对象,value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。

    function* gen(x) {
      var y = yield x + 2;
      return y;
    }
    
    var g = gen(1);
    g.next() // { value: 3, done: false }
    g.next() // { value: undefined, done: true }
    
    • Generator 函数的一个重要实际意义就是用来处理异步操作,改写回调函数。
    • Generator 函数可以暂停执行和恢复执行,这是它能封装异步任务的根本原因。
    • 除此之外,它还有两个特性,使它可以作为异步编程的完整解决方案:函数体内外的数据交换和错误处理机制。
    function* asyncJob(){
    
    // ...其他代码
    
    varf=yieldreadFile(fileA);
    
    // ...其他代码
    
    }
    

    上面代码的函数asyncJob是一个协程,它的奥妙就在其中的yield命令。它表示执行到此处,执行权将交给其他协程。
    协程遇到yield命令就暂停,等到执行权返回,再从暂停的地方继续往后执行。
    它的最大优点,就是代码的写法非常像同步操作。

    async函数

    async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await
    async告诉这个函数里面有await

    async function getTitle(url) { 
      let response = await fetch(url); 
      let html = await response.text(); 
      return html.match(/<title>([\s\S]+)<\/title>/i)[1];
    }
    getTitle('https://tc39.github.io/ecma262/').then(console.log)
    
    • async函数返回一个 Promise 对象。
    • async函数内部return语句返回的值,会成为then方法回调函数的参数。async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
    • 如果await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。抛出的错误对象会被catch方法回调函数接收到。
    await拿到的东西就是promise resolve之后的值

    async 函数的实现原理,就是将 Generator 函数和自动执行器,包装在一个函数里。

    function spawn(genF) {
        return new Promise(function(resolve, reject) {
            var gen = genF();
            function step(nextF) {
                try {
                    var next = nextF();
                } catch (e) {
                    return reject(e);
                }
                if (next.done) {
                    return resolve(next.value);
                }
                Promise.resolve(next.value).then(function(v) {
                    step(function() { return gen.next(v); });
                }, function(e) {
                    step(function() { return gen.throw(e); });
                });
            }
            step(function() { return gen.next(undefined); });
        });
    }
    

    比较

    一个异步展示动画的程序

    // Promise写法
    function chainAnimationPromise(elem, animations) {
        var ret = null;
        var p = Promise.resolve();
    
        for (var anim of animations) {
            p = p.then(function(val) {
                ret = val;
                return anim(elem);
            });
        }
    
        return p.catch(function(e) {
    
        }).then(function() {
            return ret;
        });
    }
    
    // Generator写法
    function chainAnimationPromise(elem, animations) {
        return spawn(function* () {
            var ret = null;
            try {
                for (var anim of animations) {
                    ret = yield anim(elem);
                }
            } catch (error) {
                
            }
            return ret;
        });
    }
    
    // async写法
    async function chainAnimationPromise(elem, animations) {
        var ret = null;
        try {
            for(var anim of animations) {
                ret = await anim(elem);
            }
        } catch (error) {
            
        }
        return ret;
    }
    

    相关文章

      网友评论

          本文标题:理解ES6的异步方案Promise/Generator/asyn

          本文链接:https://www.haomeiwen.com/subject/mlnmjxtx.html