深入理解Promise

一、区别实例对象和函数对象

  • 实例对象通过new构造函数构建的对象
function Fn(name) {
    this.name = name;
    this.getName = function() {
        console.log('My name is ' + this.name);
    }
}

// 实例对象 
var obj = new Fn('Herry'); // Fn是构造函数,obj是对象实例
obj.getName(); // My name is Herry
var res = Fn('Json'); // Fn作为普通函数的调用, res则是函数返回值
console.log(res); // undefined
  • 函数对象:通常将函数作为对象使用
//函数对象
var xiaoming = {};
Fn.call(xiaoming); // Fn为函数对象   call可以用来调用函数(包括构造函数)并且可以调用另一个对象的方法

var person1 = {
    name: 'person1',
    say: function() {
        console.log(this.name + ' say...');
    }
}

var person2 = {
    name: 'person2'
};
person1.say.call(person2); // person2 say...  可以看出person2并没有say方法,但person2可以调用person1的方法
  • 工厂模式
    在函数内创建一个对象,在该对象中添加属性和方法并返回该对象,使得通过普通的函数调用也能得到一个对象。
function Person(name) {
    var obj = {};
    obj.name = name;
    obj.getName = function() {
        console.log(name);
    }
    return obj;
}

var p1 = new Person('p1');
var p2 = Person('p2');
p1.getName(); // p1
p2.getName(); // p2

二、两种类型的回调函数

1. 回调函数的概念

回调函数就是一个通过函数指针调用的函数。

  • 通俗理解:函数的参数是一个function
  • 进一步理解,根据函数参数执行的先后顺序划分出了同步和异步回调
  • 个人理解:被作为参数传递到另一个函数(主函数)的那个函数就叫做回调函数
2. 回调函数的类型
  • 同步回调
    立即执行,直到执行结束。不会放到回调队列
  • 异步回调
    不会立即执行,而是放到回调队列中将来执行
// 同步回调
var arr = [1,2,3];
arr.forEach(item => { // 循环遍历的回调
    console.log(item); //不进入回调队列,立刻执行
})
console.log(4); // 先输出123 后输出4

// 异步回调
setTimeout(() => {
    console.log(1); // 进入回调队列排队
}, 0);
//总是执行完下面的代码,最后才执行回调队列里面的函数
console.log(2); // 先输出2 后输出1

三、Javascript的Error处理

1.错误类型
  • Error: 所有错误的父类型
  • ReferenceError: 引用的变量不存在
  • TypeError: 数据类型不正确
  • RangeError: 数据值不在其允许的范围之内
  • SyntaxError: 语法错误
// 常见的错误类型
// ReferenceError: 引用变量不存在
console.log(a); // ReferenceError: a is not defined

// TypeError: 数据类型不正确
var obj = {};
obj.say(); // TypeError: obj.say is not a function

// RangeError: 数据值不在其所允许的范围内
function fn(){
  fn()
}
fn()  // RangeError: Maximum call stack size exceeded

// SyntaxError: 语法错误
var str = "abc'; // SyntaxError: Invalid or unexpected token
2.错误处理
  • 错误捕获 (try...catch)
try {
    var obj = {};
    obj.say(); // 改行代码已经出错,但以下的代码还继续执行
} catch (error) {
    console.log(error.message);
    // console.log(error.stack);
}
console.log('error after'); // 该行代码还可以继续向下执行
  • 抛出错误(throw error)
function todo() {
    if (Date.now() % 2 === 0) {
        console.log('to do...');
    } else {
        throw new Error('当前时间不能执行');
    }
}
// 情况1.直接调用
// todo(); // 如果该代码执行报错,则不会执行下面的语句
// console.log('todo after');

// 情况2.捕获处理异常
try {
    todo();
} catch (e) {
    console.log(e.message);
}
console.log('哈哈,奈何不了孤王!'); // 该代码照常执行下去

四、Promise的理解和使用

1.Promise是什么?
  • Promise的概念

    1. Promise是js进行异步编程中新的解决方案(抽象)。
    2. Promise是一个构造函数(语法上)。
    3. Promise对象用来封装一个异步操作并可以获取其结果(功能上)。
  • Promise的状态改变 (重点)

    1. pending (待定的) -> fulfilled(满足的)
    2. pending (待定的) -> rejected (拒绝的)
      *注: Promise 状态的改变只有以上两种,并且一个Promise 对象状态只能改变一次,无论成功还是失败,都有一个结果数据,成功的一般称为value,失败的一般称为reason。
  • Promise的基本流程图

    Promise的基本流程图.png

  • Promise的基本使用
// 1.创建一个新的Promise对象
new Promise((resolve, reject) => {
    // 执行器函数
    console.log('执行excutor'); // 立即执行(同步回调)
    // 2. 执行异步任务
    setTimeout(() => {
        const time = Date.now();
        if (time % 2 === 0) {
            // 3.1成功回调,调用resolve(value)
            resolve("success callback, time = " + time);
        } else {
            // 3.2失败回调,调用reject(reason)
            reject("failure callback, time = " + time);
        }
    }, 0);
}).then(
    value => { // 接收到成功回调的数据value
        console.log(value);  // success callback, time = 1586874397480
    },
    reason => { // 接收到失败回调的数据reason
        console.log(reason); // failure callback, time = 1586874438679
    }
);
console.log(4);
/*以上代码的执行顺序为:
    执行excutor
    4
    success callback, time = 1586874397480 || failure callback, time = 1586874438679
*/
2.为什么要用Promise?
  • 指定回调函数的方式更灵活。(时间问题)
    1)在没有Promise之前一般使用纯回调函数,纯回调函数必须在启动异步任务之前指定回调函数(successCallback和failureCallback)
    【指定回调函数 => 启动异步任务】
// 纯回调函数 必须先指定回调函数,后执行异步任务
// 成功的回调函数
function successCallback(result){
  console.log('file created successful' + result);
}

// 失败的回调函数
function failureCallback(error){
  console.log('file created failure' + error);
}
// 伪代码
createFileAsync(fileConfig, successCallback, failureCallback);

2)用了Promise之后可以先启动异步任务(甚至异步任务执行结束之后或得到结果数据后),再指定回调函数,仍然能接收到结果数据。
【启动异步任务(任务结束)=> 指定回调函数】

const p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success');
        // reject('failure');
    }, 100);
})
p.then(value => {
    console.log(value); // success
}, reason => {
    console.log(reason);
})
  • 支持链式调用,可以解决回调地狱问题
    1.什么是回调地狱 ?回调函数作为参数层层嵌套,外层回调函数异步执行后返回的结果数据作为内层嵌套回调函数执行的条件
    2.回调地狱的缺点?不便于阅读 和 不便于异常处理
    3.有什么解决方案Promise链式调用
    4.终极解决方案async/await
// 回调地狱伪代码
todo1(function(res1) {
    todo2(res1, function(res2) {
        todo3(res2, function(res3) {
            console.log('res3' + res3);
        }, failureCallback)
    }, failureCallback)
}, failureCallback)

// 使用Promise链式调用伪代码
todo1()
    .then(function(res1) {
        return todo2(res1);
    })
    .then(function(res2) {
        return todo3(res2);
    })
    .then(function(res3) {
        console.log('res3' + res3);
    })
    .catch(failureCallback)

// async/await伪代码
async function request() {
    try {
        const res1 = await todo1();
        const res2 = await todo2(res1);
        const res3 = await todo3(res2);
        console.log('res3' + res3);
    }catch(error){
        failureCallback(error);
    }
}
3.Promise如何使用?
1) Promise构造函数:

*注: excutor会在Promise内部立即执行同步回调,而异步操作会在执行器(excutor)中执行

Promise(excutor)
excutor参数:同步执行 (resolve, reject) => { }
resolve参数:内部定义成功时调用的函数 value => { }
reject参数:内部定义失败时调用的函数 reason => { }

2) Promise.prototype.then()

*注: onFulfilled指定成功的回调,成功的值为value。onRejected指定失败的回调,失败的值为reason,并返回一个新的promise对象

Promise.prototype.then(onFulfilled, onRejected)
onFulfilled参数:成功的回调函数 value => { }
onRejected参数:失败的回调函数 reason => { }

3) Promise.prototype.catch()

*注: then方法的语法糖,相当于then(null, onRejected)

Promise.prototype.catch(onRejected => {})
onRejected参数:失败的回调函数 reason => { }

4) Promise.resolve()

*注: 返回一个成功或失败的Promise对象, 状态由value决定,如果value是带有then方法的对象,则最终状态由then方法执行的结果决定;如果value为空,基本数据类型或者不带then方法的对象, 返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。

Promise.prototype.resolve(onFulfilled => {})
onFulfilled参数:成功或失败的回调 value => { }

5) Promise.reject()

*注: 返回一个失败的promise对象,并把失败信息reason传递给对应的处理方法。

Promise.reject(error)
error参数:失败结果,其失败的结果会给处理失败的方法处理

6) Promise.all()

*注: 返回一个新的Promise, 当promises中所有对象都成功, 才返回成功的状态, 其成功的返回值跟promises数组顺序保持一致;否则,一旦有一个promise失败,则返回失败的状态,其失败的返回值则会把promises里第一个触发失败的promise对象的错误信息返回

Promise.all ( promises )
promises参数:Promise对象实例的数组

7) Promise.race()

*注: 返回一个新的Promise对象, 其最终状态第一个完成的Promise的结果状态决定

Promise.race ( promises )
promises参数:Promise对象实例的数组

duck.gif

你可能感兴趣的:(深入理解Promise)