Promise学习总结

了解promise诞生的历史背景


1.词语本意解释

promise [ˈprɑ:mɪs] 许诺;允诺;(有可能)
从字面意思,表示一个将来的状态。
用在异步操作里面,帮我们去处理一件未来可能发生的一件什么事。

2.MDN解释
  • promise对象用于异步计算
  • 一个promise表示一个现在、将来或永远不可能可用的值。
3.按照用途来解释
  • 主要用来异步计算
  • 可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果。
  • 可以在对象之间传递和操作promise,帮助我们处理队列。
4.为什么会有Promise?
  • JavaScript包含大量异步操作
    • JavaScript为检查表单而生。
    • 创造它的首要目标是操作DOM
    • 所以,JavaScript的操作大多是异步的。
5.为什么异步操作可以避免界面冻结呢?
  • 假设你去到一家饭店,自己找座坐下了,然后招呼服务员拿菜单。
  • 服务员说:“对不起,我是同步服务员,我要服务完这张桌子才能招呼你。”
  • 你是不是很想抽ta?
  • 那一桌人明明已经吃上了,你只是想要菜单,这么小的一个动作,服务员却要你等到别人的一个大动作完成。
  • 这就是同步的问题: 顺序交付的工作1234,必须按照1234的顺序完成。
  • 异步,则是将耗时很长的A交付的工作交给系统之后,就去继续做B交付的工作。等到系统完成前面的工作之后,再通过回调或者事件,继续做A剩下的工作。
  • 从观察者的角度看起来,AB工作的完成顺序,和交付他们的时间顺序无关,所以叫"异步"。
6.异步操作的常见语法
  • 事件侦听与响应
document.getElementById('start').addEventListener('click', start, false);

function start() {
    // 响应事件,进行相应的操作
}

// jQuery 用 `.on()` 也是事件侦听
$('#start').on('click', start);
  • 回调
// 比较常见的有ajax
$.ajax('http://baidu.com', {
    success: function (res) {
        // 这里就是回调函数了
    }
});

// 或者在页面加载完毕后回调
$(function(){
    // 这里也是回调函数
});
7.浏览器中的JavaScript
  • 异步操作以事件为主,如ready、onload
  • 回调主要出现在Ajax和file API
    这个时候问题尚不算严重
8.有了Node.js之后

对异步的依赖进一步加剧了...
Node.js出现了的时候,PHP、JAVA、Python这些服务器端的语言都已经很成熟了。Node.js作为一个后来者,想要从中分一杯羹,必须有自己的绝活。

  • 无阻塞高并发,是Node.js的招牌
  • 异步操作是其保障。
  • 大量操作依赖回调函数。
9.使用Node.js开发时的问题
  • 不好维护
    稍有不慎,就会踏入“回调地狱”
a(function (resultsFromA) {
    b(resultsFromA, function (resultsFromB) {
        c(resultsFromB, function (resultsFromC) {
            d(resultsFromC, function (resultsFromD) {
                e(resultsFromD, function (resultsFromE) {
                    f(resultsFromE, function (resultsFromF) {
                        console.log(resultsFromF);
                    })
                })
            })
        })
    })
});
  • 除此之外,还有更深层次的问题
    遍历目录,找出最大的一个文件。
这段代码跑在node环境中,使用一些node模块。
const fs = require('fs');  //文件系统
const path = require('path');

function findLargest(dir, callback) {
    fs.readdir(dir, function (err, files) {
    //用fs.readdir读文件夹的内容。传入回调函数
        if (err) return callback(err); // [1]
        //如果发现错误,就用回调函数传出错误

        //如果读出来就执行下面操作
        let count = files.length; // [2]
        //取出来文件数量
        let errored = false;
        let stats = [];
        files.forEach( file => {  //对文件进行遍历
            fs.stat(path.join(dir, file), (err, stat) => {
            //每一个文件都用fs.stat去取状态。取出状态用到回调函数
                if (errored) return; // [1]
                //发生错误,中断,return掉
                if (err) {
                    errored = true;
                    return callback(err);
                }
                stats.push(stat); // [2]
                //没有发生错误,把stat文件放入数组

                if (--count === 0) {  //用count变量来计数,每读完一个文件,都减一,当到0的时候,就认为所有文件都读完了
                    let largest = stats  //然后对数组进行遍历,找出其中
                        .filter(function (stat) { return stat.isFile(); })
                        .reduce(function (prev, next) {
                            if (prev.size > next.size) return prev;
                            //找出其中最大的文件信息,用下面的callback返回
                            return next;  //记下内容
                        });
                    callback(null, files[stats.indexOf(largest)]);
                    //第一个参数,是否有参数,因为是正常的,所以返回null
                }
            });
        });
    });
}

findLargest('./path/to/dir', function (err, filename) {
//使用的时候调用,'传入要查找的目录',传入回调函数
//回调函数接受两个参数。“错误”,“文件名”
    if (err) return console.error(err);  
    //如果有错误,就返回错误信息。
    console.log('largest file was:', filename);
    //没有错误,返回文件名
});
//在标记的地方有问题,以后补充问题

异步回调有四个问题

  • 嵌套层次很深,难以维护
  • 无法正常使用return 和 throw
  • 无法正常检索堆栈信息
  • 多个回调之间难以建立联系

Promise入门

1.Promise简介
new Promise(
    /* 执行器 executor */
    function (resolve, reject) {
        // 一段耗时很长的异步操作
        resolve(); // 数据处理完成
        reject(); // 数据处理出错
    }
)
    .then(function A() {
        // 成功,下一步
    }, function B() {
        // 失败,做相应处理
    });
2.Promise详解
  • Promise是一个代理对象,它和原先要进行的操作并无关系。
  • 它通过引入一个回调,避免更多的回调。
3.Promise有三个状态:
  • pending [待定] 初始状态
  • fulfilled [实现] 操作成功
  • rejected [被否决] 操作失败

Promise状态发生改变,就会触发.then()里的响应函数处理后续步骤
Promise状态一经改变,不会再变。


4.范例
  • 定时执行
console.log('here we go');
new Promise( resolve => {
    setTimeout( () => {
        resolve('hello');
    }, 2000);
})
    .then( value => {
        console.log( value + ' world');
    });

//输出结果
here we go
hello world  //2秒之后输出
5.两步执行范例
  • 分两次,顺序依次执行
console.log('here we go');
new Promise( resolve => {
    setTimeout( () => {
        resolve('hello');
    }, 2000);
})
    .then( value => {
        console.log(value);
        return new Promise( resolve => {
            setTimeout( () => {
                resolve('world');
            }, 2000);
        });
    })
    .then( value => {
        console.log( value + ' world');
    });

//输出结果
here we go
hello  //2秒
world world  //2秒
6.已完成的Promise,再执行.then()
console.log('start');

let promise = new Promise(resolve => {
    setTimeout(() => {
        console.log('the promise fulfilled');
        resolve('hello, world');
    }, 1000);
});

setTimeout(() => {
    promise.then( value => {
        console.log(value);
    });
}, 3000);

//输出结果
start
the promise fulfilled  //1秒之后输出
hello, world  //再过2秒之后输出
7.在.then()的函数里面不返回新的Promise,会怎么样?
console.log('here we go');
new Promise(resolve => {
    setTimeout( () => {
        resolve('hello');
    }, 2000);
})
    .then( value => {
        console.log(value);
        console.log('everyone');
        (function () {
            return new Promise(resolve => {
                setTimeout(() => {
                    console.log('Mr.Laurence');
                    resolve('Merry Xmas');
                }, 2000);
            });
        }());
        return false;  //没有等待里面的promise执行
        //但是里面的定时器仍在等待执行
        //在promise里面如果不直接返回一个promise实例
        //就会默认执行下一个环节
        //即使返回false也不影响下一组,false作为直接传递到下一组
    })
    .then( value => {
        console.log(value + ' world');
    });

//输出结果
here we go  //先输出

hello  //这三个同时输出
everyone
false worl

Mr.Laurence  //最后输出这个
8.then()
  • .then()接受两个函数作为参数,分别代表fulfilled和rejected
  • .then() 返回一个新的Promise实例,所以它可以链式调用
  • 当前面的Promise状态改变时,.then()根据其最终状态,选择特定的状态响应函数执行。
  • 状态响应函数可以返回新的promise,或其他值
  • 如果返回新的Promise,那么下一级.then()会在新Promise状态改变之后执行。
  • 如果返回其他任何值,则会立刻执行下一级.then()

小测试

1. .then()里有.then()的情况
  • 因为.then()返回的还是Promise实例
  • 会等里面的.then()执行完,在执行外面的。
  • 对于我们来说,此时最好将其展开,会更好读。
console.log('start');
new Promise( resolve => {
    console.log('Step 1');
    setTimeout(() => {
        resolve(100);
    }, 1000);
})
    .then( value => {
        return new Promise(resolve => {
            console.log('Step 1-1');
            setTimeout(() => {
                resolve(110);
            }, 1000);
        })
            .then( value => {
                console.log('Step 1-2');
                return value;
            })
            .then( value => {
                console.log('Step 1-3');
                return value;
            });
    })
    .then(value => {
        console.log(value);
        console.log('Step 2');
    });

//输出结果
start
Step 1

Step 1-1
Step 1-2
Step 1-3

Step 2

学会使用promise解决异步回调带来的问题

掌握promise的进阶用法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335