美文网首页
Promise、Generator 函数与 async/awai

Promise、Generator 函数与 async/awai

作者: 执凉 | 来源:发表于2017-09-22 16:51 被阅读0次

    前言

    本次分享的内容是 Promise、Generator 函数与 async/await ,都是与异步操作相关的内容,我们常见的异步操作基本是:回调函数事件监听,AJAX就是事件监听的一种,本次分享中也主要以AJAX为例。

    var request = new XMLHttpRequest();
    
    request.onreadystatechange = function () {
        if (request.readyState === 4) {
            if (request.status === 200) {
                return success(request.responseText);
            } else {
                return fail(request.status);
            }
        }
    }
    
    request.open('GET', '/api/categories');
    request.send();
    

    Promise

    首先先看一下Promise是什么:

    Promise.png

    可以看到Promise是一个构造函数,里面有我们熟悉的all、 reject 、resolve 方法,原型上有 then、catch 方法,我们可以新建一个Promise 对象来使用。

    new Promise(
        /* executor */
        function(resolve, reject) {...}
    );
    

    我觉得文档上说的比我清楚的多:

    Promise对象是一个代理对象(代理一个值)。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers )。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象
    一个 Promise有以下几种状态:

    • pending: 初始状态,不是成功或失败状态。
    • fulfilled: 意味着操作成功完成。
    • rejected: 意味着操作失败。
      pending 状态的 Promise 对象可能触发fulfilled 状态并传递一个值给相应的状态处理方法,也可能触发失败状态(rejected)并传递失败信息。当其中任一种情况出现时,Promise 对象的 then 方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled 和 onrejected,它们都是 Function 类型。当Promise状态为fulfilled时,调用 then 的 onfulfilled 方法,当Promise状态为rejected时,调用 then 的 onrejected 方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)。
      因为 Promise.prototype.then 和 Promise.prototype.catch
      方法返回promise 对象, 所以它们可以被链式调用。
    promises.png
    疑问

    既然 .then() 既有reject 也有 resolve的回调,那为什么还有.catch()?

    我看网上的说法是说 如果是 .then() 中报错,则会进入 .catch() 中处理,这样可以避免报错,类似于 try catch。

    基本api
    • Promise.resolve()
    • Promise.reject()
    • Promise.prototype.then()
    • Promise.prototype.catch()
    • Promise.all() // 所有的完成
    • Promise.race() // 竞速,完成一个即可

    应用

    然后我们用Promise来重写一下ajax:

    function ajax (method, url, data) {
        var request = new XMLHttpRequest();
        return new Promise(function (resolve, reject) {
            request.onreadystatechange = function () {
                if (request.readyState === 4) {
                    if (request.status === 200) {
                        resolve(request.responseText);
                    } else {
                        reject(request.status);
                    }
                }
            };
            request.open(method, url);
            request.send(data);
        });
    }
    
    var p = ajax('GET', '/api/xxxx');
    p.then(function (text) {
        console.log(text);
    }).catch(function (status) {
        console.log('ERROR: ' + status);
    });
    

    看起来好像并没有什么改变,但是如果我们想一个请求完成再发起另一个请求呢?

    ajax ('GET',  '/api/hhh').then(function(data) {
      return ajax('POST', '/api/hhhh', data.body);
    })
    
    .then(function(data) {
      return ajax('POST', '/api/hhhhh', data.body);
    })
    
    .then(function() {
       console.log(data);
    });
    

    肯定比无限回调好看多了。

    除此之外,我们可以使用 Promise.all() 来并行执行异步操作。

    function func(num){
        var p = new Promise(function(resolve, reject){
            setTimeout(function(){
                resolve(num);
            }, 1000);
        });
        return p; 
    }
    
    Promise.all([func(1), func(2), func(3)])
    .then(function(results){
        console.log(results);
    });
    
    // console的值为 [1, 2, 3]
    

    三个异步操作的并行执行的,等到它们都执行完后才会进到then里面,all会把所有异步操作的结果放进一个数组中传给then,就是上面的results。

    Generator 函数

    之前没怎么接触过,是一个可以返回多次的函数。
    generator 函数由 function*定义,除了 return 还可以使用 yield 返回多次。那到底怎么用?

    应用

    先来个简单的例子:
    斐波那契数列,一般我们要这样写:

    function fib(max) {
        var
            t,
            a = 0,
            b = 1,
            arr = [0, 1];
        while (arr.length < max) {
            t = a + b;
            a = b;
            b = t;
            arr.push(t);
        }
        return arr;
    }
    fib(5); // [0, 1, 1, 2, 3]
    

    使用 generator:

    function* fib(max) {
        var
            t,
            a = 0,
            b = 1,
            n = 1;
        while (n < max) {
            yield a;
            t = a + b;
            a = b;
            b = t;
            n ++;
        }
        return a;
    }
    
    var f = fib(5);
    f.next(); // {value: 0, done: false}
    f.next(); // {value: 1, done: false}
    f.next(); // {value: 1, done: false}
    f.next(); // {value: 2, done: false}
    f.next(); // {value: 3, done: true}
    

    //

    相关文章

      网友评论

          本文标题:Promise、Generator 函数与 async/awai

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