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

原文地址:https://www.cnblogs.com/JoeChan/p/4943384.html