• 读书笔记-你不知道的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、决议后返回的值可以通过链式调用解决掉。

     

      

  • 相关阅读:
    Web Accessibility All In One
    CSS 3D Card Effect All In One
    Sololearn All In One
    In modern js you don't need void 0 anymore All In One
    医学科技解剖数字人 All In One
    SPAR19 航班航迹追踪 All In One
    HTML5 Games Development Foundation All In One
    HTML5 Canvas Games All In One
    python 中 如何提取或者删除列表的最后几个元素(适用于元组、字符串序列)
    c语言中输出整数类整型变量的长度(所占的字节数)
  • 原文地址:https://www.cnblogs.com/QH-Jimmy/p/6527034.html
Copyright © 2020-2023  润新知