zoukankan      html  css  js  c++  java
  • Promise

    这样一个场景,两个异步请求,第二个需要用到第一个请求成功的数据
    ajax({
            url: url1,
            success: function(data) {
                ajax({
                    url: url2,
                    data: data,
                    success: function() {
                    }
                });
            }
        });

    如果继续下去在回调函数中进行下一步操作,嵌套的层数会越来越多。我们可以进行适当的改进,把回调函数写到外面

    function A() {
            ajax({
                url: url1,
                success: function(data) {
                    B(data);
                }
            });
        }
        function B(data) {
            ajax({
                url: url2,
                success: function(data) {
                    ......
                }
            });
        }

    即使是改写成这样,代码还是不够直观,如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doom)。有了Promise对象,代码就可以写得非常清晰

    new Promise(A).done(B);

    Promises 将嵌套的 callback,改造成一系列的.then的连缀调用,去除了层层缩进的糟糕代码风格。Promises 不是一种解决具体问题的算法,而已一种更好的代码组织模式。

    各个语言平台都有相应的 Promise 实现

    • Java's java.util.concurrent.Future
    • Python's Twisted deferreds and PEP-3148 futures
    • F#'s Async
    • .Net's Task
    • C++ 11's std::future
    • Dart's Future
    • Javascript's Promises/A/B/D/A+
    var val = 1;
    // 我们假设step1, step2, step3都是ajax调用后端或者是
    // 在Node.js上查询数据库的异步操作
    // 每个步骤都有对应的失败和成功处理回调
    // 需求是这样,step1、step2、step3必须按顺序执行
    function step1(resolve, reject) {
        console.log('步骤一:执行');
        if (val >= 1) {
            resolve('Hello I am No.1');
        } else if (val === 0) {
            reject(val);
        }
    }
    
    function step2(resolve, reject) {
        console.log('步骤二:执行');
        if (val === 1) {
            resolve('Hello I am No.2');
        } else if (val === 0) {
            reject(val);
        }
    }
    
    function step3(resolve, reject) {
        console.log('步骤三:执行');
        if (val === 1) {
            resolve('Hello I am No.3');
        } else if (val === 0) {
            reject(val);
        }
    }
    
    new Promise(step1).then(function(data){
        console.info(data);
        return new Promise(step2);
    },function(data){
        console.log("执行reject方法");
        return ;
    }).then(function(data){
        console.info(data);
        return new Promise(step3);
    }).then(function(data){
        console.info(data);
        return data;//返回“Hello I am No.3”
    }).then(function(data){
        console.info(data);
        return data;
    });

    输出

    步骤一:执行
    Hello I am No.1
    步骤二:执行
    Hello I am No.2
    步骤三:执行
    Hello I am No.3
    Hello I am No.3
    Promise的意义就在于 then 链式调用 ,它避免了异步函数之间的层层嵌套,将原来异步函数的嵌套关系 转变为便于阅读和理解的 链式步骤关系 。
    Promise构造函数只接受一个参数,即带有异步逻辑的函数。这个函数在 new Promise 时已经执行了。只不过在没有调用 then 之前不会 resolve 或 reject。
    在then方法中通常传递两个参数,一个 resolve 函数,一个 reject 函数。reject就是出错的时候运行的函数罢。resolve 函数必须返回一个值才能把链式调用进行下去。
    • resolve 返回一个新 Promise,返回一个新Promise之后再调用的then就是新Promise中的逻辑了。
    • resolve 返回一个值,返回一个值会传递到下一个then的resolve方法参数中。

    基本的 api

    1. Promise.resolve()
    2. Promise.reject()
    3. Promise.prototype.then()
    4. Promise.prototype.catch()
    5. Promise.all() // 所有的完成 
    6. Promise.race() // 竞速,完成一个即可
    Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 方法和 reject 方法。
    如果异步操作成功,则用 resolve 方法将 Promise 对象的状态,从「未完成」变为「成功」(即从 pending 变为 resolved);
    如果异步操作失败,则用 reject 方法将 Promise 对象的状态,从「未完成」变为「失败」(即从 pending 变为 rejected)。
     
    catch的用法,它和then的第二个参数一样,用来指定reject的回调
    getNumber()
    .then(function(data){
        console.log('resolved');
        console.log(data);
    })
    .catch(function(reason){
        console.log('rejected');
        console.log(reason);
    });

    效果和写在then的第二个参数里面一样。不过它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中。

     
    Promise的all方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。
    Promise
    .all([runAsync1(), runAsync2(), runAsync3()])
    .then(function(results){
        console.log(results);
    });
    用Promise.all来执行,all接收一个数组参数,里面的值最终都算返回Promise对象。这样,三个异步操作的并行执行的,等到它们都执行完后才会进到then里面。那么,三个异步操作返回的数据哪里去了呢?都在then里面呢,all会把所有异步操作的结果放进一个数组中传给then,就是上面的results。
    race的用法,all方法的效果实际上是「谁跑的慢,以谁为准执行回调」,那么相对的就有另一个方法「谁跑的快,以谁为准执行回调」,这就是race方法,这个词本来就是赛跑的意思。
     
    Promise
    .race([runAsync1(), runAsync2(), runAsync3()])
    .then(function(results){
        console.log(results);
    });

    在then里面的回调开始执行时,runAsync2()和runAsync3()并没有停止,仍旧再执行。于是再过1秒后,输出了他们结束的标志。

    Promise 对象有以下两个特点。
    (1)对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    (2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果。就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。
     
    有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
    Promise 也有一些缺点。首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

    参考:

  • 相关阅读:
    Task10 文本预处理
    Task09 批量归一化
    Task06 Basic of CNN
    Task05 梯度消失和梯度爆炸
    Task 04 过拟合,欠拟合及其解决方案
    机器学习 Task 03 多层感知机
    机器学习 task2 softmax与分类模型
    异步与闭包与fetch
    baidu API
    my own JSON
  • 原文地址:https://www.cnblogs.com/chenlogin/p/5313590.html
Copyright © 2011-2022 走看看