puddlejumper26 / blogs

Personal Tech Blogs
4 stars 1 forks source link

Promise 【ES6】of JS [ 原理,例子 ] #176

Open puddlejumper26 opened 3 years ago

puddlejumper26 commented 3 years ago

1.0 什么是 Promise

Promise 的特点

Promise A+规范

Promise 优点

Promise 缺点

1.1 几种常见异步编程方案

E.g. Callback function

$.get(url, (data) => {
    console.log(data)
)
$.get(url, data1 => {
    console.log(data1)
    $.get(data1.url, data2 => {
        console.log(data1)
    })
})

1.2 问题

1.3 Promise 处理多个相互关联的异步请求

const request = url => { 
    return new Promise((resolve, reject) => {
        $.get(url, data => {
            resolve(data)
        });
    })
};

// 请求data1
request(url).then(data1 => {
    return request(data1.url);   
}).then(data2 => {
    return request(data2.url);
}).then(data3 => {
    console.log(data3);
}).catch(err => throw new Error(err));
puddlejumper26 commented 3 years ago

2.0 Promise 的基本方法【then】, 【catch】, 【promise chain】

2.1 Then

promise.then(onFulfilled, onRejected)
promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

2.2 Catch

promise.catch(onRejected)
相当于
promise.then(null, onRrejected);

// 注意
// onRejected 不能捕获当前onFulfilled中的异常
promise.then(onFulfilled, onRrejected); 

// 可以写成:
promise.then(onFulfilled)
       .catch(onRrejected);   

2.3 Promise Chain

function taskA() {
    console.log("Task A");
}
function taskB() {
    console.log("Task B");
}
function onRejected(error) {
    console.log("Catch Error: A or B", error);
}

var promise = Promise.resolve();
promise
    .then(taskA)
    .then(taskB)
    .catch(onRejected) // 捕获前面then方法中的异常

Source

puddlejumper26 commented 3 years ago

3.0 With Promise 和 Without

Without

With

puddlejumper26 commented 3 years ago

4.0 Promise 运用原理和源码的实现流程

macrotasks: script(整体代码),setTimeout,setInterval,setImmediate,I/O,UI rendering,event listner

microtasks: process.nextTick, Promises, Object.observe, MutationObserver

Source

puddlejumper26 commented 3 years ago

4.1 极简的实现

//极简的实现
class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
    }
    _resolve(value) {
        this.callbacks.forEach(fn => fn(value));
    }
}

//Promise应用
let p = new Promise(resolve => {
    setTimeout(() => {
        console.log('done');
        resolve('5秒');
    }, 5000);
}).then((tip) => {
    console.log(tip);
})

代码运行的步骤

Step 1 image

Step 2 image

Step 3 image

Step 4 image

等待1秒钟 Step 5 image

这里console出现 done

Step 6 image

Step 7 image

Step 8 image

这里console出现 5秒钟

Step 9 image

Step 10 image

Step 11 image

Source

puddlejumper26 commented 3 years ago

4.2 极简的实现+链式调用

//极简的实现+链式调用
class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
        return this;                           <======
    }
    _resolve(value) {
        this.callbacks.forEach(fn => fn(value));
    }
}

let p = new Promise(resolve => {
    setTimeout(() => {
        console.log('done');
        resolve('5秒');
    }, 5000);
}).then(tip => {
    console.log('then1', tip);
}).then(tip => {
    console.log('then2', tip);
});

代码运行的步骤

Step 1 image

Step2 image

Step 3 image

Step 4 image

这里要过5秒钟 Step 5 image

这里出现 done

Step 6 image

Step 7 image

Step 8 image

这里出现 then1 5秒钟

Step 9 image

Step 10 image

Step 11 image

这里出现 then2 5秒钟

Step 12 image

Step 13 image

Step 14 image

Step 15 image

puddlejumper26 commented 3 years ago

4.3 极简的实现+链式调用+延迟机制

//极简的实现+链式调用+延迟机制
class Promise {
    callbacks = [];
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        this.callbacks.push(onFulfilled);
        return this;
    }
    _resolve(value) {
        setTimeout(() => {//看这里
            this.callbacks.forEach(fn => fn(value));
        });
    }
}

let p = new Promise(resolve => {
    console.log('同步执行');
    resolve('同步执行');
}).then(tip => {
    console.log('then1', tip);
}).then(tip => {
    console.log('then2', tip);
});

setTimeout(() => {
    p.then(tip => {
        console.log('then3', tip);
    })
});

代码运行的步骤

Step 1 image

Step 2 image

Step 3 image

Step 4 image

这里出现 同步执行

Step 5 image

Step 6 image

Step 7 image

Step 8 image

这里出现 then1 同步执行

Step 9 image

Step 10 image

Step 11 image

这里出现 then2 同步执行

Step 12 image

Step 13 image

Step 14 image

Step 15 image

Step 16 image

Step 17 image

Step 18 image

Source

https://zhuanlan.zhihu.com/p/58428287

puddlejumper26 commented 3 years ago

4.4 极简的实现+链式调用+延迟机制+状态

//极简的实现+链式调用+延迟机制+状态
class Promise {
    callbacks = [];
    state = 'pending';//增加状态
    value = null;//保存结果
    constructor(fn) {
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        if (this.state === 'pending') {//在resolve之前,跟之前逻辑一样,添加到callbacks中
            this.callbacks.push(onFulfilled);
        } else {//在resolve之后,直接执行回调,返回结果了
            onFulfilled(this.value);
        }
        return this;
    }
    _resolve(value) {
        this.state = 'fulfilled';//改变状态
        this.value = value;//保存结果
        this.callbacks.forEach(fn => fn(value));
    }
}
let p = new Promise(resolve => {
    console.log('同步执行');
    resolve('同步执行');
}).then(tip => {
    console.log('then1', tip);
}).then(tip => {
    console.log('then2', tip);
});

setTimeout(() => {
    p.then(tip => {
        console.log('then3', tip);
    })
});

代码运行的步骤

Step 1 image

Step 2 image

Step 3 image

Step 4 image

Step 5 image

Step 6 image

这里出现 同步执行

Step 7 image

Step 8 image

Step 9 image

Step 10 image

Step 11 image

Step 12 image

Step 13 image

Step 14 image

Step 15 image

Step 16 image

Step 17 image

这里出现 then1 同步执行

Step 18 image

Step 19 image

Step 20 image

Step 21 image

Step 22 image

Step 23 image

这里出现 then2 同步执行

Step 24 image

Step 25 image

Step 26 image

Step 27 image

Step 28 image

Step 29 image

Step 30 image

这里出现 then3 同步执行

Step 31 image

Step 32 image

Step 33 image

Step 34 image

Source

https://zhuanlan.zhihu.com/p/58428287

puddlejumper26 commented 3 years ago

4.5 链式调用的实现

let promiseCount = 1;
//完整的实现 测试Demo
class Promise {
    callbacks = [];   
    name = '';
    state = 'pending';//增加状态
    value = null;//保存结果
    constructor(fn) {
        this.name = `Promse-${promiseCount++}`;
        console.log('[%s]:constructor', this.name);
        fn(this._resolve.bind(this));
    }
    then(onFulfilled) {
        console.log('[%s]:then', this.name);
        return new Promise(resolve => {
            this._handle({
                onFulfilled: onFulfilled || null,
                resolve: resolve
            });
        });
    }
    _handle(callback) {
        console.log('[%s]:_handle', this.name, 'state=', this.state);

        if (this.state === 'pe`nding') {
            this.callbacks.push(callback);
            console.log('[%s]:_handle', this.name, 'callbacks=', this.callbacks);
            return;
        }
        //如果then中没有传递任何东西
        if (!callback.onFulfilled) {
            callback.resolve(this.value);
            return;
        }
        var ret = callback.onFulfilled(this.value);
        callback.resolve(ret);
    }
    _resolve(value) {
        console.log('[%s]:_resolve', this.name);
        console.log('[%s]:_resolve', this.name, 'value=', value);

        if (value && (typeof value === 'object' || typeof value === 'function')) {
            var then = value.then;
            if (typeof then === 'function') {
                then.call(value, this._resolve.bind(this));
                return;
            }
        }

        this.state = 'fulfilled';//改变状态
        this.value = value;//保存结果
        this.callbacks.forEach(callback => this._handle(callback));
    }
}

/**
 * 模拟异步请求
 * @param {*} url 
 * @param {*} s 
 * @param {*} callback 
 */
const mockAjax = (url, s, callback) => {
    setTimeout(() => {
        callback(url + '异步请求耗时' + s + '秒');
    }, 1000 * s)
}

new Promise(resolve => {
    mockAjax('getUserId', 1, function (result) {
        resolve(result);
    })
}).then(result => {
    console.log(result);
    //对result进行第一层加工
    let exResult = '前缀:' + result;
    return exResult;
}).then(exResult => {
    console.log(exResult);
});

20201129_010430

当第一个 Promise 成功时,resolve 方法将其状态置为 fulfilled ,并保存 resolve 带过来的value。然后取出 callbacks 中的对象,执行当前 Promise的 onFulfilled,返回值通过调用第二个 Promise 的 resolve 方法,传递给第二个 Promise。

代码运行的步骤

Step 1 image

Step 2 image

Step 3 image

Step 4 image

Step 5 image

Step 6 image

Step 7 image

Step 8 image

Step 9 image

console.log -- > [Promise-1]:constructor

Step 10 image

Step 11 image

Step 12 image

Step 13 image

这一步的结果 image

Step 14 image

Step 15 image

增加的 --> promise.html:52 [Promse-1]:_resolve

Step 16 image

增加的 --> promise.html:53 [Promse-1]:_resolve value= getUserId异步请求耗时1秒

Step 17 image

Step 18 image

Step 19 image

Step 20 image

Step 21 image

增加了 --> promise.html:36 [Promse-1]:_handle state= fulfilled

Step 22 image

Step 23 image

Step 24 image

Step 25 image

增加了 --> promise.html:86 getUserId异步请求耗时1秒

Step 26 image

Step 27 image

Step 28 image

Step 29 image

增加了 --> promise.html:52 [Promise-2]:_resolve

Step 30 image

增加了 --> promise.html:53 [Promse-2]:_resolve value= 前缀:getUserId异步请求耗时1秒

Step 31 image

Step 32 image

Step 33 image

Step 34 image

Step 35 image

增加了 --> promise.html:36 [Promse-2]:_handle state= fulfilled

Step 36 image

Step 37 image

Step 38 image

Step 39 image

增加了 --> promise.html:91 前缀:getUserId异步请求耗时1秒

Step 40 image

Step 41 image

Step 42 image

增加了 --> promise.html:52 [Promise-3]:_resolve

Step 43 image

增加了 --> promise.html:53 [Promise-3]:_resolve value = undefined

Step 44 image

Step 45 image

Step 46 image

Step 47 image

Step 48 image

Step 49 image

Step 50 image

Step 51 image

Step 52 image

Step 53 image

Step 54 image

Step 55 image

Step 56 image

Console.log

image

Source

https://zhuanlan.zhihu.com/p/102017798

puddlejumper26 commented 3 years ago

4.5 Promise 原型方法的实现

代码运行的步骤

Step 1

Step 2

Step 3

Step 4

Step 5

Step 6

Step 7

Step 8

Step 9

Step 10

Step 11

Step 12

Step 13

Step 14

Step 15

Step 16

Step 17

Step 18

Step 19

Step 20

Step 21

Step 22

Step 23

Step 24

Step 25

Step 26

Step 27

Step 28

Step 29

Step 30

Step 31

Step 32

Step 33

Step 34

Step 35

Step 36

Step 37

Step 38

Step 39

Step 40

Step 41

Step 42

Step 43

Step 44

Step 45

Step 46

Step 47

Step 48

Step 49

Step 50

Step 51

Step 52

Step 53

Step 54

Step 55

Step 56

Step 57

Step 58

Step 59

Step 60

puddlejumper26 commented 3 years ago

4.6 Promise 静态方法的实现

代码运行的步骤

Step 1

Step 2

Step 3

Step 4

Step 5

Step 6

Step 7

Step 8

Step 9

Step 10

Step 11

Step 12

Step 13

Step 14

Step 15

Step 16

Step 17

Step 18

Step 19

Step 20

Step 21

Step 22

Step 23

Step 24

Step 25

Step 26

Step 27

Step 28

Step 29

Step 30

Step 31

Step 32

Step 33

Step 34

Step 35

Step 36

Step 37

Step 38

Step 39

Step 40

Step 41

Step 42

Step 43

Step 44

Step 45

Step 46

Step 47

Step 48

Step 49

Step 50

Step 51

Step 52

Step 53

Step 54

Step 55

Step 56

Step 57

Step 58

Step 59

Step 60

puddlejumper26 commented 3 years ago

5.0 Promise 练习题

5.1

const promise = new Promise((resolve, reject) => {
  console.log(1)
  resolve()
  console.log(2)
})
promise.then(() => {
  console.log(3)
})
console.log(4)

//运行结果:
1
2
4
3

5.2

const promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('success')
  }, 1000)
})
const promise2 = promise1.then(() => {
  throw new Error('error!!!')
})

console.log('promise1', promise1)
console.log('promise2', promise2)

setTimeout(() => {
  console.log('promise1', promise1)
  console.log('promise2', promise2)
}, 2000)

//运行结果:
promise1 Promise { <pending> }
promise2 Promise { <pending> }
Uncaught (in promise) Error: error!!!
promise1 Promise { <fulfilled>'success' }
promise2 Promise {
  <rejected> Error: error!!!
    at promise.then (...)
    at <anonymous> }

5.3

5.4

5.5

5.6

5.7

5.8

5.9

5.10

5.11

5.12

Source

https://juejin.cn/post/6844903509934997511 https://www.jianshu.com/p/52fda0f4003a