zoukankan      html  css  js  c++  java
  • Promise/Generator/Co

    ---恢复内容开始---

    这三个都是为解决回调而生的, 最近在学习Koa框架, Koa框架主要就是将异步的写法变成的同步, 解决了回调地狱的问题,也易于流程的控制, 于是找了很多篇文章学习, 终于有点感悟了~ >-<

    1、Promise 

          看名字,Promise(承诺), 很容易联想到, 这个应该是异步操作结果的承诺, 就像数据库操作, 我们要先去find(), find到了之后就去save(), 那我们承诺find到结果后就去save, 这样就实现了异步写法变同步写法 Promise.then(DB.save(){}) 这样,我们就解决了一些些回调函数的问题了

          还是比较正式一些介绍一下Promise:这是一个对象, 用于传递异步操作的信息。

      它的特点

    1、Promise对象代表一个异步操作, 有三种状态 Pending(进行中) Resolve(已完成) Reject(已失败) 只有异步操作的结果可以决定当前的状态
    2、Promise对象的状态改变: Pending=>Resolved , Pending=>Rejected

      基本用法

    var promise = new Promise(function (resolve, reject) {
        if (find得了数据成功) {
            resolve(数据);
        } else {
            reject(err)
        }
    })
    
    
    //通过Generator部署Ajax操作
    function *main() {
        var result = yield request('...');
        var resp = JSON.parse(result);
        console.log(resp.value);
    }
    function request(url) {
        makeAjaxCall(url, function(response) {
            it.next(response);//参数加上response, 作为result的值,否则返回的是undefined
        })
    }
    var it = next();
    it.next();
    //解决回调地狱
    step1(function (value1) {
       step2(value1, function(value2) {
          dothing...     
       }) 
    })
    
    //如果用Promise改写的化
    Q.fcall(step1)
        .then(step2)//step1,2都是异步操作
        .then(function(){
           dosth... 
        }, function(err) {
           doerr... 
        })
        .done();
    
    //用generator控制流程
    function* longRunningTask() {
        try {
            var value1 = yield step1();
            var value2 = yield step2(value1);
        } catch(e) {
            s....
        }
    }
    //这个函数按次序自动执行所有步骤
    function scheduler(task) {
        setTimeout(function() {
            var taskObj = task.next(task.value);
            if (!taskObj.done) {
                task.value = taskObj.value;
                scheduler(task)'
            }
        }, 0);
    }
    
    
    
    /Promise实例生成后, 用then方法分别制定Resolve和Reject的回调函数
    promise.then(functioin(数据) {
        dealWith(数据);
        }, function(err) {
        handout)(err)
        }
    )
    //异步加载图片
    function loadImageAsync(url) {
        return new Promise(function(resolve, reject) {
            var image = new Image(); //异步加载一张图片
            image.onload = function() {
                resolve(image);//加载成功把image传给承诺的下个函数作为参数
            }
            image.onerror = function() {
                reject(new Error('Could not load image at + 'url');
            }
            image.src = url;
        })           
    }
    //异步操作的结果是另一个异步操作
    var p1 = new Promise(function (resolve, reject) {
        doSomething();
    })
    var p2 = new Promise(function (resolve, reject) {
        resolve(p1); //p2需要等待p1的状态进行下一步操作, 等于数据库的save需要等待find的状态,这两个就是两个异步操作
    })
    //Promise.then
    //上面的可以用这个栗子改写
    DB.find('someFile').then(
        file => save(file.AAA)
    ).then(
        AAA => doSomething(AAA),
        err   => console.log(err)
    );
    //Promise.all用于将多个Promise包装成一个实例
    var promises = [1, 2, 3, 4, 5, 6, 7].map(function(id) {
        return getJSON(id + '.json'); //Promise函数
    })
    Promise.all(promises).then(function(posts) {
        do(posts);
    }).catch(function(reason) {
    }
    //Generator和Promise
    //Generator用于管理流程
    function getFoo() {
        return new Promise(function(resolve, reject) {
            resolve('foo');//返回一个Promise对象
        })
    }
    
    var g = function *() {
        try{
            var foo = yield getFoo(); //迭代器到这里才会运行
            console.log(foo);
        } catch (e) {
            console.log(e);
        }
    }
    // 简单的co
    function run(generator) {
        var it = generator(); //生成迭代器实例
        function go(result) {
            if (result.done) {
                return result.value;
            }
            return result.value.then(function (value) {
                return go(it.next(value));
            }, function(err) {
                return go(it.throw(error));
            })'
        }
        go(it.next()); //启动迭代器遍历
    }
    
    run(g)
    2、Generator

    可以把Generotor看成一个状态机, 封装了内部状态

    执行Generator函数返回一个遍历器对象, 调用遍历器对象的next方法可以使得遍历的指针向下走

    //生成一个Generator对象
    function *asd() {
        yield 'joe';
        yield 'chan';
        return 'done';
    }
    var asd = asd();
    asd.next()
    // { value: 'joe', done: false }
    
    asd.next()
    // { value: 'chan', done: false }
    
    asd.next()
    // { value: 'done', done: true }
    
    asd.next()
    // { value: undefined, done: true }

    //遇到yield暂停后面的操作, yield后面的表达式的值作为返回对象的value
    //yield语句没有返回值(总是返回undefined),next(arg)中的arg就被当作上一个yield语句的返回值
    //上面最后一点的一个应用
    function *foo(x) {
        var y = 2* (yield x);
        var z = yield y;
        return z+y
    }
    var foo = foo(5);
    foo,next() //{value:5, done: false}
    foo.next() //{value:NaN, done: false} //因为yield的返回值是undefined
    
    foo.next(12) //{value: 24, done: false} //传入参数当作上一次yield的返回值

     异步操作的同步化表达

    function *loadUI() {
        showLoadingScreen();
        yield loaUIAsyncchoromously();//异步操作
        hideLoadingScreen(); //异步操作的后续操作(原来的回调函数)
    }
    var loader = loadUI();
    //加载UI
    loader.next();
    ...
    //卸载UI
    loader.next();
    //通过Generator函数部署Ajax操作
    function* main() {
      var result = yield request("http://...");
      var resp = JSON.parse(result);
        console.log(resp.value);
    }//同步方式表达Ajax
    
    function request(url) {
      makeAjaxCall(url, function(response){
        it.next(response);//response作为result的值, 
      });
    }
    
    var it = main();
    it.next();//开始遍历迭代器

    经典的回调hell

    step1(function (value1) {
      step2(value1, function(value2) {
        dosth...
      });
    });
    
    //用Promise改写上面的代码
    fcall(step1)
      .then(step2)
      .then(function (value2) {
        do...
      }, function (error) {
        doerr
      })
      .done();



    //
    Generator函数控制代码运行流程
    function* longRunningTask() {
      try {
        var value1 = yield step1();
        var value2 = yield step2(value1);
        //do...
      } catch (e) {
        doerr
      }
    }//同步控制流程

    scheduler(longRunningTask());
    function scheduler(task) {
      setTimeout(function() {
        var taskObj = task.next(task.value); //异步操作
    
        if (!taskObj.done) {
          task.value = taskObj.value
          scheduler(task);
        }
      }, 0);
    }
    

    参考

    http://es6.ruanyifeng.com/#docs/generator

  • 相关阅读:
    LA 6621 /ZOJ 3736 Pocket Cube 打表+暴力
    UVA 10273
    UVA 10158 并查集的经典应用
    CodeForces 382B 数学推导
    UVA 10806 最小费用最大流
    UVA 10330 最大流
    图论:匹配与覆盖+独立集 团与支配集
    sdut oj 操作系统实验--SSTF磁盘调度算法【操作系统算法】
    【转载】单调队列学习
    poj 3006 Dirichlet's Theorem on Arithmetic Progressions【素数问题】
  • 原文地址:https://www.cnblogs.com/JoeChan/p/4943384.html
Copyright © 2011-2022 走看看