JS:异步总结

2018-01-12  本文已影响0人  sinbad_3815

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

回调函数

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

有一些问题:

事件监听

发布/订阅

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

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

参考:

上一篇 下一篇

猜你喜欢

热点阅读