美文网首页
JS:异步总结

JS:异步总结

作者: sinbad_3815 | 来源:发表于2018-01-12 00:40 被阅读0次

如果需要执行一段异步代码,js有以下几种方案:

回调函数

setTimeout(function(){
    setTimeout(function(){
        setTimeout(function(){
                ......
        })
    })
})

有一些问题:

  • 层层嵌套,代码难看,不优雅
  • try{}cattch()难捕获异常
  • 不能return

事件监听

发布/订阅

Promise

  1. Promise是一个类,类的构造函数接收一个task任务函数,该函数接收两个JavaScript引擎提供的两个参数resolve, reject
  2. 立即执行传入的task函数
  3. 如果操作(一般是异步操作)成功,调用resolve方法,并把异步的结果传入,如果传入的是一个promise,则自己的状态无效,传入的promise的状态决定了该promise的状态,如果传入的不是一个promise,resolve方法会把等待状态变成成功状态(pending -> resolved);如果操作(一般是异步操作)失败,调用reject方法,并把异步的结果传入,reject方法会把等待状态变成失败状态(pending -> rejected)。
  4. then方法指定回调函数,接收两个回调函数resolve, reject。当状态从pengding->resolved时,执行resolve,如果resolve的结果是一个promise,这是后面一个回调函数会等待该promise完成后执行;当状态从pengding->rejected时,执行reject。
  5. then方法返回一个新的Promise实例(不是原来的Promise),因此可以链式调用。

下面是模拟ES6,自己代码代码实现Promise:

function Promise(task) {
    var t = this;
    t.value;
    t.statues = "pending";
    t.resolveCallbacks = [];
    t.rejectCallbacks = [];
    function resolve(value){
        if(value instanceof Promise){
            value.then(resolve, reject);
        }else{
            t.statues = "fufilled";
            t.value = value;
            t.resolveCallbacks.forEach(item=>item(value));
        }
    }
    function reject(value){
        if(value instanceof Promise){
            value.then(resolve, reject);
        }else{
            t.statues = "rejected";
            t.value = value;
            t.rejectCallbacks.forEach(item=>item(value));
        }
    }
    try{
        task(resolve, reject);
    }catch(e){
        reject(e);
    }
}
function resolvePromise(x, resolve, reject){
    if(x instanceof Promise){
        if(x.statues == "fufilled"){
            resolve(x.value);
        }else if(x.statues == "rejected"){
            reject(x.value);
        }else{
            x.then(function (y) {
                resolvePromise(y, resolve, reject);
            }, reject)
        }
    }else if(x != null && (typeof x == "object" || typeof x == "function")){
        let then = x.then;
        if(typeof then == "function"){
            x.then.call(x, function (y2) {
                resolvePromise(y2, resolve, reject);
            }, reject)
        }
    }else{
        resolve(x);
    }
}

Promise.prototype = {
    then: function (resolveCall, rejectCall) {
        let t = this;
        let promise2;
        resolveCall = typeof resolveCall == "function" ? resolveCall : function () {
            return t.value;
        }
        rejectCall = typeof rejectCall == "function" ? rejectCall : function () {
            return t.value;
        }
        if(t.statues == "fufilled"){
            promise2 = new Promise(function (resolve, reject) {
                let x = resolveCall(t.value);
                resolvePromise(x, resolve, reject);
            })

        }else if(t.statues == "rejected"){
            promise2 = new Promise(function (resolve, reject) {
                let x = rejectCall(t.value);
                resolvePromise(x, resolve, reject);
            })
        }else if(t.statues == "pending"){
            promise2 = new Promise(function (resolve, reject) {
                t.resolveCallbacks.push(function () {
                    resolvePromise(resolveCall(t.value), resolve, reject);
                });
                t.rejectCallbacks.push(function () {
                    resolvePromise(rejectCall(t.value), resolve, reject);
                });
            })
        }
        return promise2;
    }
}

// 快捷方法
Promise.resolve = function (value) {
    return new Promise(function(resolve, reject){
        resolve(value);
    });
}
Promise.reject = function (value) {
    return new Promise(function(resolve, reject){
        reject(value);
    });
}

// 所有成功resolve,否则reject
Promise.all = function (promises) {
    if(!Array.isArray(promises)){
        return TypeError("参数类型错误");
    }
    return new Promise(function (resolve, reject) {
        let result = [];
        let index = 0;
        if(promises.length > 0){
            for(let i = 0; i<promises.length; i++){
                promises[i].then(function (value) {
                    index++;
                    result[i] = value;
                    if(index == promises.length){
                        resolve(result);
                    }
                }, function (value) {
                    reject(value);
                })
            }
        }
    })
}

// 竞速,谁跑得快先返回谁
Promise.race = function (promises) {
    if(!Array.isArray(promises)){
        return TypeError("参数类型错误");
    }
    return new Promise(function (resolve, reject) {
        if(promises.length > 0){
            for(let i = 0; i<promises.length; i++){
                promises[i].then(function (value) {
                    resolve(value);
                }, function (value) {
                    reject(value);
                })
            }
        }
    })
}

module.exports = Promise;

Generator

  • Generator可以暂停函数执行,返回任意表达式的值。
  • Generator函数有两个特征,一是,function关键字和函数名之间有个*号,二是,函数体内部使用yield表达式。
  • 调用Generator并不执行,返回的是遍历器对象(Iterator)。调用Iterator的next方法后,函数内部指针从函数头部或者上一次停下来的地方开始执行,直到遇到下一个yield表达式。
  • 遇到yield表达式,next函数返回一个对象形如{value: , done: false|true}形式,表达式的value值是yield后面的表达式值或者最后的return值,如果没有return,函数执行完,value值就是undefined。yield表达式的返回值是next函数的传入值或者undefined。
function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}

var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }

for...of循环

for...of循环自动遍历Generator函数生成的Iterator对象,不需要使用next()。

另外,也可以使用拓展运算符(...)、解构赋值,Array.from方法内部调用的,都是遍历器接口。因此:

function* numbers () {
  yield 1
  yield 2
  return 3
  yield 4
}

// 扩展运算符
[...numbers()] // [1, 2]

// Array.from 方法
Array.from(numbers()) // [1, 2]

// 解构赋值
let [x, y] = numbers();
x // 1
y // 2

// for...of 循环
for (let n of numbers()) {
  console.log(n)
}
// 1
// 2

async

  • async函数是Generator函数的语法糖。
  • async函数返回一个Promise对象

参考:

相关文章

网友评论

      本文标题:JS:异步总结

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