Promise学习笔记

Posted 二木成林

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Promise学习笔记相关的知识,希望对你有一定的参考价值。

注:笔记来自于视频尚硅谷Web前端Promise教程从入门到精通
注:如果是初学仅需要学会Promise的基本使用即可,不要陷入要自己实现手写Promise中。

Promise的理解和使用

Promise是什么

  • Promise是一门新的技术,ES6技术规范。
  • Promise是javascript进行异步编程的新解决方案。旧方案是单纯使用回调函数。
  • 从语法上来说,Promise是一个构造函数。
  • 从功能上来说,promise对象用来封装一个异步操作并可以获取其成功和失败的结果值。

JavaScript中常见的异步编程场景有:

  • fs模块文件操作:require('fs').readFile('./test.txt', (err,data)=>);
  • 数据库操作
  • Ajax:$.get('/server', (data)=>);
  • 定时器:setTimeout(()=>, 2000);

Promise的出现解决了回调地狱的问题:

// 所谓的回调地狱就是在回调函数中不断嵌套回调函数
asyncFunc1(opt, function (args1) 
    asyncFunc2(opt, function (args2) 
        asyncFunc3(opt, function (args3) 
            asyncFunc4(opt, function (args4) 
                // ...
            )
        )
    )
);

Promise的语法格式如下:

var promise = new Promise(function (resolve, reject) 
    // resolve和reject两个都是函数类型的参数
    // 当成功时调用resolve()函数
    // 当失败时调用reject()函数
    if (/*异步操作成功*/)
        resolve([成功参数列表]);
     else 
        reject([失败参数列表]);
    
);
promise.then(function ([成功参数列表]) 
    // 当执行成功时调用的方法,即resolve
, function ([失败参数列表]) 
    // 当执行失败时调用的方法,即reject
);

案例

获取随机数来打印字符串

使用异步编程实现,如下:

setTimeout(function () 
    var random = Math.ceil(Math.random() * 10);
    // 如果随机数大于5则直接输出随机数的值;如果随机数小于等于5则循环打印"hello world"
    if (random > 5) 
        console.log("random = " + random);
     else 
        for (var i = 0; i < random; i++) 
            console.log("hello world");
        
    
, 3000);

在一个setTimeout()函数中又嵌套了另外一个setTimeout()函数,都是异步操作。如果改成使用Promise来实现,则代码如下:

var promise = new Promise(function (resolve, reject) 
    setTimeout(function () 
        // 获取一位随机数
        var random = Math.ceil(Math.random() * 10);
        if (random > 5) 
            // 当随机数大于5时,我们设定为异步操作成功了
            // 调用resolve()函数,并且传入一个参数
            resolve(random);
         else 
            // 当随机数小于等于5时,我们设定为异步操作失败了
            // 调用reject()函数,并且传入一个对象参数
            reject(random: random, text: "hello world");
        
    , 100)
);
promise.then(function (random) 
    // 当异步操作成功时执行的函数,即resolve()
    console.log("random = " + random);
, function (obj) 
    // 当异步操作失败时执行的函数,即reject()
    for (var i = 0; i < obj.random; i++) 
        console.log(obj.text);
    
);

文件读取

使用fs模块的readFile()方法读取文件内容,用回调函数方式实现如下:

var fs = require('fs');
// 文件读取操作readFile()函数是一个异步操作
fs.readFile('./text.txt', function (err, data) 
    if (err) 
        // 如果文件读取发生错误,则打印错误对象
        console.log(err);
     else 
        // 如果文件读取成功,则打印文件内容
        console.log(data.toString())
    
);

使用Promise进行改写,代码如下:

var fs = require('fs');
// 文件读取操作readFile()函数是一个异步操作
var promise = new Promise(function (resolve, reject) 
    fs.readFile('./text.txt', function (err, data) 
        if (err) 
            // 如果文件读取失败,则调用reject函数
            reject(err);
         else 
            // 如果文件读取成功,则调用resolve函数
            resolve(data.toString());
        
    );
);
promise.then(function (content) 
    // 当异步操作成功调用的函数,即resolve
    console.log(content.toUpperCase());
, function (err) 
    // 当异步操作失败调用的函数,即reject
    console.log(err)
);

原生Ajax

使用原生Ajax来发送一个GET请求,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<script type="text/javascript">
    // 1.创建对象
    var xhr = new XMLHttpRequest();
    // 2.初始化
    xhr.open('GET', 'http://poetry.apiopen.top/sentences ');
    // 3.发送
    xhr.send();
    // 4.处理响应结果
    xhr.onreadystatechange = function () 
        if (xhr.readyState === 4) 
            // 判断响应状态码 2xx
            if (xhr.status >= 200 && xhr.status < 300) 
                // 控制台输出响应体
                console.log(xhr.response)
             else 
                console.log(xhr.status)
            
        
    ;
</script>
</body>
</html>

使用Promise改写后,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<script type="text/javascript">
    var promise = new Promise(function (resolve, reject) 
        // 1.创建对象
        var xhr = new XMLHttpRequest();
        // 2.初始化
        xhr.open('GET', 'http://poetry.apiopen.top/sentences ');
        // 3.发送
        xhr.send();
        // 4.处理响应结果
        xhr.onreadystatechange = function () 
            if (xhr.readyState === 4) 
                // 判断响应状态码 2xx
                if (xhr.status >= 200 && xhr.status < 300) 
                    // 当响应成功则调用resolve函数
                    resolve(xhr.response);
                 else 
                    // 当响应失败则调用reject函数
                    reject(xhr.status)
                
            
        ;
    );
    promise.then(function (response) 
        // 当异步操作成功后调用的方法,即resolve
        console.log(response);
    , function (reason) 
        // 当异步操作失败后调用的方法,即reject
        console.log(reason);
    );
</script>
</body>
</html>

Promise封装fs模块读取操作

使用Promise封装fs模块读取文件的操作,代码如下:

/**
 * 封装一个函数来读取文件内容
 * @param path 文件内容
 * @returns Promise<any> Promise对象
 */
function readFile(path) 
    return new Promise(function (resolve, reject) 
        var fs = require('fs');
        fs.readFile(path, function (err, data) 
            if (!err) 
                resolve(data.toString());
             else 
                reject(err);
            
        );
    );


// 调用函数
readFile('./text.txt')
    .then(function (data) 
        console.log(data);
    , function (err) 
        console.log(err);
    );

Promise封装Ajax操作

使用Promise封装Ajax的GET请求,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<script type="text/javascript">
    /**
     * 封装一个Ajax操作
     * @param method 请求方式GET或POST
     * @param url 请求路径
     * @returns Promise<any> Promise对象
     */
    function ajax(method, url) 
        return new Promise(function (resolve, reject) 
            // 1.创建对象
            var xhr = new XMLHttpRequest();
            // 2.初始化
            xhr.open(method, url);
            // 3.发送
            xhr.send();
            // 4.处理响应结果
            xhr.onreadystatechange = function () 
                if (xhr.readyState === 4) 
                    // 判断响应状态码 2xx
                    if (xhr.status >= 200 && xhr.status < 300) 
                        // 当响应成功则调用resolve函数
                        resolve(xhr.response);
                     else 
                        // 当响应失败则调用reject函数
                        reject(xhr.status)
                    
                
            ;
        )
    

    // 发送Ajax请求
    ajax('GET', 'http://poetry.apiopen.top/sentences')
        .then(function (response) 
            // 当异步操作成功后调用的方法,即resolve
            console.log(response);
        , function (reason) 
            // 当异步操作失败后调用的方法,即reject
            console.log(reason);
        );
</script>
</body>
</html>

Promise的状态

Promise只会发生两种改变:

  • pending状态变成resolved状态
  • pending状态变成rejected状态

只有这两种,且一个Promise对象只能改变一次,无论变成成功还是失败,都会有一个结果数据,成功的结果数据一般称为value,失败的结果数据一般称为reason。注意:value和reason只是形参的名字,可自定义。

promise实例对象中的一个属性state表示Promise的状态,它有三个值:

  • pending:表示未决定成功还是失败的状态。
  • resolved(或fullfilled):表示成功的状态。
  • rejected:表示失败的状态。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<script type="text/javascript">
    // pending状态
    var promise1 = new Promise(function (resolve, reject) 
        // 既不调用resolve又不调用reject则是pending状态
    );
    console.log(promise1);
    // resolved(fullfilled)状态
    var promise2 = new Promise(function (resolve, reject) 
        // 调用resolve变成resoled状态
        resolve('Success');
    );
    console.log(promise2);
    // rejected状态
    var promise3 = new Promise(function (resolve, reject) 
        // 调用reject变成rejected状态
        reject('Error');
    );
    console.log(promise3);
</script>
</body>
</html>

Promise的基本流程

如何使用Promise?

Promise的API

1、Promise构造函数:Promise(excutor)

  • executor是一个函数,表示执行器。即function(resolve, reject)
  • resolve是一个回调函数,当在Promise中成功时则调用该函数。
  • reject也是一个回调函数,当在Promise中失败时调用该函数。

注:executor会在Promise内部立即同步调用,异步操作在执行器中执行。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<script type="text/javascript">
    /*
        new Promise(excutor); 构造函数,返回一个Promise对象
     */
    var promise = new Promise(function (resolve, reject) 
        // 当成功时调用resolve函数
        // 当失败时调用reject函数
    );
</script>
</body>
</html>

2、Promise.prototype.then方法:promise.then(onResolved, onRejected)

  • onResolved函数,即成功时的回调函数。即function(value)
  • onRejected函数,即失败时的回调函数。即function(reason)

注:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,返回一个新的Promise对象。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<script type="text/javascript">
    var promise = new Promise(function (resolve, reject) 
        // 当成功时调用resolve函数
        // 当失败时调用reject函数
    );
    // 返回一个新的Promise对象
    var newPromise = promise.then(function (value) 
        // 成功的回调函数,即resolve
    , function (reason) 
        // 失败的回调函数,即reject
    );
</script>
</body>
</html>

4、Promise.prototype.catch方法:promise.catch(onRejected)

  • onRejected函数:失败的回调函数,即function(reason)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
</head>
<body>
<script type="text/javascript">
    var promise1 = new Promise(function (resolve, reject) 
        // 修改promise对象的状态
        reject('Error');
    );
    promise1.catch(function (reason) 
        // catch只有在失败状态时才会调用
        console.log(reason);
    );

    var promise2 = new Promise(function (resolve, reject) 
        // 修改promise对象的状态。当修改为成功的状态则不会调用catch的回调函数
        resolve('Success');
    );
    promise2.catch(function (reason) 
        // 因为Promise对象是成功状态,该catch内的回调函数不会被调用
        console.log(reason);
    )
</script>
</body>
</html>

4、Promise.resolve方法

<!DOCTYPE html>
<html lang="en">
<head<

以上是关于Promise学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记:python3,代码片段(2017)

Promise学习笔记

Promise学习笔记

《Promise学习笔记》- 2Promise相关常用方法总结

Promise/commonJS/AMD学习笔记

es6学习笔记--promise对象