# 期约与异步函数

同步行为与异步行为的统一是计算机科学的一个基本概念

# 前置 同步与异步

同步行为对应内存中顺序执行的处理器指令

let a = 3
a = a + 4

异步行为类似于系统中断,当前进程的外部实体可以触发代码的执行

let a = 3
setTimeout(()=> a = a + 4, 1000)
  • 上述两段代码有相同的低级代码,但setTimeout中的累加、赋值操作是由计时器而非流水指令触发,会形成一个入队执行的中断,这对于js运行时来说是黑盒,js为了让后续代码能使用a,需要一种知道a何时可读取的机制

# 史前的异步编程模式

只支持定义异步回调函数表明异步操作完成,而串联异步操作是常见的,因此产生了回调地狱问题

function double(value){
    setTimeout(() => setTimeout(console.log, 0, value * 2), 1000)
}

double(3) // 6
// 异步返回值

# promiseA+

# 前置 测试套件

npm install promises-aplus-tests

# 术语

  • promise 是一个包含 then 方法的对象或函数,该方法符合规范指定的行为。

  • thenable 是一个包含 then 方法和对象或者函数。

  • value 就是任意合法 JS 值。

  • exception 就是 throw 语句抛出的值。

  • reason 是一个指示 promise 为什么被 rejected 的值。

# Promise 状态

  • 在 pending 状态,promise 可以切换到 fulfilled 或 rejected。

  • 在 fulfilled 状态,不能迁移到其它状态,必须有个不可变的 value。

  • 在 rejected 状态,不能迁移到其它状态,必须有个不可变的 reason。

状态流转如下:

pending -> resolve(value) -> fulfilled

pending -> reject(reason) -> rejected

const PENDING = 'pending'
const REJECTED = 'rejected'
const FULFILLED = 'fulFilled'

function promise() {
    this.state = PENDING;
    this.result = null;
}

const transition = (promise, state, result) => {
    if(promise !== PENDING) return;
    promise.state = state;
    promise.result = result;
}

## Then 方法
- promise 必须有 then 方法,接受 onFulfilled 和 onRejected 参数。
``js
Promise.property.then = function(onFulFilled, onRejected){
    
}

- onFulfilled必须是函数类型,可选,如果不是函数,应该被忽略。
    - 只能被调用一次(实现时需使用变量来限制执行次数)
    - 在promise变成fulfilled之前,不应该被调用
    - 在promise变为fulfilled时,应该调用onFulfilled,参数是value
- onRejected必须是函数类型,可选,如果不是函数,应该被忽略。
    - 只能被调用一次
    - 在promise变成rejected之前,不应该被调用
    - 在promise变成rejected时,应该调用onRejected,参数是reason
- then 方法可以被调用很多次,每次注册一组 onFulfilled 和 onRejected 的 callback。它们如果被调用,必须按照注册顺序调用,因此then 方法必须返回 promise,从而构成了promise的链式调用(回调地狱的由来)。

- onFulfilled和onRejected应该是微任务
> onFulfilled or onRejected must not be called until the execution context stack contains only platform code.

``js
function Promise(){
    this.state = PENDING;
    this.result = null;
    this.callbacks = [];
}

promise2 = promise.then(onFulFilled, onRejected) 

===Promise.prototype.then = function(onFulFilled, onRejected){
    // 返回promise
    return new Promise((resolve, reject) => {
        let callback = {onFulfilled, onRejected, resolve, reject}

        if(this.state===PENDING){
            // 链式顺序调用
            this.callbacks.push(callback)
        }else{
            // 微任务入栈,确保顺序调用
            setTimeout(()=>handleCallback(callback, this.state, this.result), 0)
        }
    })
}

const handleCallback = (callback, state, result) => {
    let { onFulfilled, onRejected, resolve, reject } = callback
    try {
        if (state === FULFILLED) {
            resolve(onFulfilled(state))
        } else if(state === REJECTED) {
            resolve(onRejected(state))
        }
    } catch (error) {
        reject(error)
    }
}

## The Promise Resolution Procedure
- 如果 result 是当前 promise 本身,就抛出 TypeError 错误。
- 如果 result 是另一个 promise,那么沿用它的 state 和 result 状态。
- 如果 result 是一个 thenable 对象。先取 then 函数,再 call then 函数,重新进入 The Promise Resolution Procedure 过程。
- 如果不是上述情况,这个 result 成为当前 promise 的 result。
``js
const resolvePromise = (promise, result, resolve, reject) => {
    if(result === promise){
        let reason = new TypeError('Can not fufill promise with itself');
        return reject(reason)
    }

    if(isPromise(result)){
        return result.then(resolve, reject)
    }

    if(isThenable(result)){
        try{
            let then = result.then;
            if(isFunction(then)){
                return new Promise(then.bind(result).then(resolve, reject))
            }
        }catch(error){  
            return reject(error)
        }
    }
}