读书笔记-你不知道的JS中-promise(2)

继续填坑

模式

  考虑下面的代码:

    function fn(x) {
        //do something
        return new Promise(function(resolve, reject) {
            //调用resolve(..)和reject(...)
        });
    }
    var p = fn(2);

  new Promise(..)模式通常称为revealing constructor。传入函数会立即执行(不会像then(..)中的回调一样异步延迟),它有两个参数,分别为resolve和reject。这些是promise的决议函数。resolve通常标识完成,reject标识拒绝。

鸭子类型

  如何判断一个对象是不是一个Promise?虽然promise是通过new Promise(..)创建的,但是无法通过instanceof Promise来检测,最主要的原因是promise可能来自其他的窗口,检查无法识别这样的Promise实例。

  识别Promise的方法被定义为是否具有then方法。也就是说,任何对象和函数,如果有then(包括原型链上)方法,就认为是一个Promise对象。

  逻辑大概如下:

    if (
        p !== null &&
        (typeof p === 'object' || typeof p === 'function') &&
        typeof p.then === 'function'
    ) {
        //这是一个promise对象
    }

Promise特点

  1、对一个Promise调用then时,提供的回调永远会被异步调用。

  2、只要promise被决议,提供给then的回调会被自动调用,永远返回一个值。

 

promise与竞态

  虽然说一旦promise被决议,后续then方法的回调一定会被调用,但是决议本身未被执行,只能通过别的机制来强制执行:

    //必须返回一个promise
    function delay(time) {
        return new Promise(function(resolve, reject) {
            setTimeout(function() {
                reject('time out');
            }, time);
        });
    }
    //3秒内未决议就会被reject
    Promise.race(p, delay(3000)).then(function() {
        //success
    }, function(err) {
        //failed
    })

  

Promise异常

  考虑下面的代码:

    var p = new Promise(function(resolve, reject) {
        //异常
        fo();
    })
    p.then(function(data) {
        console.log(data);
    }, function() {
        //这个reject接受了异常 并又搞出了一个异常
        foo();
    }).then(function() {

    }, function() {
        //这个reject处理了最后的异常
        console.log(1);
    });

  可以看出,每一个then方法会返回一个promise,并且一旦决议就不会改变,异常会转接到下一个then的reject。

 Promise的回调

  看起来promise也是利用回调函数完成异步操作,但是有一些不同。

关于Promise.resolve(..)

  如果向Promise.resolve(..)传递一个非Promise、非thenable(即有then方法的对象或函数)的立即值,就会得到一个用这个值填空的promise,相当于包装。

  下面两种情况,p1和p2的行为是一样的:

    var p1 = new Promise(function(resolve, reject) {
        resolve(42);
    });
    var p2 = Promise.resolve(42);
    console.log(p2); //Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 42}

  而如果向Promise.resolve(..)传递一个真正的Promise,就只会返回同一个promise。

    var p1 = Promise.resolve(42);
    var p2 = Promise.resolve(p1);
    console.log(p1 === p2); //true

  如果向Promise.resolve(..)传递了一个非Promise的thenable值,前者会试图展开这个值,而且展开过程会持续到提取出一个具体的非类Promise的最终值。

  比如说:

    var p = {
        then: function(resolve, reject) {
            resolve(42);
            // reject('123');
        }
    };
    p.then(function resolve(val) {
        console.log(val);
    }, function reject(err) {
        console.log(err);
    });
    Promise.resolve(p); //打印42 得到一个Promise

  Promise.resolve(..)可以接受任何thenable,将其解封为非thenable的值。从Promise.resolve(..)得到的肯定是一个Promise,是一个可信任的值。

  将一个未知工具封装Promise并解析,可以这样:

    Promise.resolve('tool').then(function(val) {
        console.log(val);
    });

  这样,可以将所有未知封装为Promise,保证异步调用。

 

 链式调用

  可以把多个Promise连接到一起以表示一系列异步步骤:

  1、每次调用then(..),它都会创建并返回一个新的Promise,我们可以将其链接起来。

  2、不管从then(..)调用的完成回调返回的值是什么,都会被设置为被链接Promise。

  不太懂啊:

    var p = Promise.resolve(2);
    var p2 = p.then(function(v) {
        console.log(v); //2
        return v * 2;
    });
    p2.then(function(v) {
        console.log(v); //4
    });

  通过Promise.resolve对2进行封装,调用第一个then方法得到数据2。接着返回一个包含4的Promise封装对象,由调用then方法获取到4。

  只要通过return和then方法,就能实现Promise链式调用。

Ajax案例

  链式调用可以与ajax完美结合,如下例:

    //假设存在方法ajax(url,callback)
    function request(url) {
        return new Promise(function(resolve, reject) {
            //ajax的回调函数是promise的resolve()函数
            ajax(url, resolve);
        });
    }
    //异步请求返回数据data
    request('http://...').then(function(data) {
        //将返回的数据拼接到第二个url作为参数再次请求
        return request('http://...?data=' + data);
    }).then(function(data2) {
        //得到最终数据
        console.log(data2);
    });

  如果then方法参数未提供resolve或者reject,会有一个默认的函数生成,如下例:

    Promise.resolve(2).then(
        //function(v){
        //    return v;
        //}
        null,
        function() {
            console.log(1);
        }).then(function(v) {
            console.log(v); //2
        },
        //默认错误处理函数
        //function(err) {
        // throw err;
        //}
    );

   

  小结:1、调用Promise.resolve(..)与then(..)总会返回一个Promise。

     2、决议后返回的值可以通过链式调用解决掉。

 

  

原文地址:https://www.cnblogs.com/QH-Jimmy/p/6527034.html