Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promise #1

Open
AILINGANGEL opened this issue May 15, 2019 · 0 comments
Open

Promise #1

AILINGANGEL opened this issue May 15, 2019 · 0 comments

Comments

@AILINGANGEL
Copy link
Owner

AILINGANGEL commented May 15, 2019

1.Promise包含三种状态,pending, fullfilled, rejected

image

2.Promise 的优缺点

优点:

  • 解决回调地域的问题
  • 解决信任问题;在回调函数中把自己的函数交有第三方控制执行,可能会导致没有执行,提前执行,过早执行,执行多次的问题

缺点:

  • 单一值: resolve或者reject只能接受单个的值,如果想要决议多个值,需要将这些值封装在一个数组或者一个对象中
  • 异常捕获的问题: 前一个promise的异常只能被下一个catch或者reject回调捕获。但是如果catch或者reject回调自己也有异常呢?

3.Promise的特点

  • excutor函数接受resolve和reject两个参数
  • excutor函数是同步执行的,then是异步执行的; 即使在excutor函数中没有异步代码,then也是被异步执行
new Promise(function(resolve, reject) {
    console.log('start excutor');
    resolve(100);
    console.log('after resolve');
}).then(function(data) {
    console.log('success', data);
}, function(error) {
    console.log('error', error);
});
console.log('start before then');
// start excutor
// after resolve
// start before then
// success 100
  • 单决议: 一旦决议(resolve或者reject)之后决议结果不能再改变;注意单决议不是说后面的代码不执行了,在excutor函数里只要不return不管是resolve还是reject之后的代码都依然会执行。
new Promise(function(resolve, reject) {
    setTimeout(function() {
        console.log('before resolve');
        resolve(4, 3); // 首次决议,then的resolved回调接收结果
        console.log('after resolve'); // 决议不影响后面的代码执行
        reject(5); // 已经决议过不会被reject的回调接受
        console.log('after reject');//依然会执行
        return 'test'; // return的结果并不会被then的回调函数接收
        console.log('after return'); // 不会执行
    }, 500);
}).then(function(data) {
    console.log(data);// 只会打印4,传递给resolve的第二个参数3被忽略
}, function(error) {
    console.log(error);
});
// before resolve
// after resolve
// after reject
// 4

4.关于then

  • 每次调用then或者catch都会返回一个新的promise
let p1 = new Promise(function(resolve, reject) {
    resolve(100);
});
let p2 = p1.then(function(data) {
    return data;
});
console.log(p1 === p2)// false
  • then中的返回结果会作为下一次then的结果。在then中可以使用return含义不同于在excutor函数中使用return;
  • 在then中使用return 返回一个基本类型的值会被作为下一次的成功态
new Promise(function(resolve, reject) {
    resolve(100);
}).then(function(data) {
    return data;
}).then(function(data) {
    console.log('success', data); // 走到这里, success 100
}, function(error) {
    console.log('error', error);
});
  • 在then中不显示调用return则就当做return undefined来处理
new Promise(function(resolve, reject) {
    resolve(100);
}).then(function(data) {
    // return data;
}).then(function(data) {
    console.log('success', data); // 走到这里, success undefined
}, function(error) {
    console.log('error', error);
});
  • 在then中(完成回调或拒绝回调)可以return一个promise,这个promise会被展开。就是下一个then中收到的结果是这个return promise的结果,这个promise是成功的就走成功回调,是失败的就走失败回调。
new Promise(function(resolve, reject) {
    resolve(100);
}).then(function(data) {
    return new Promise(function(resolve, reject) {
        resolve(data * 2);
    });
}).then(function(data) {
    console.log('success', data);// 走到这里 success 200
}, function(error) {
    console.log('error', error);
});

new Promise(function(resolve, reject) {
    resolve(100);
}).then(function(data) {
    return new Promise(function(resolve, reject) {
        reject(data * 2);
    });
}).then(function(data) {
    console.log('success', data);
}, function(error) {
    console.log('error', error); // 走到这里 error 200
});

new Promise(function(resolve, reject) {
    reject(100);
}).then(function(data) {
    throw new Promise(function(resolve, reject) {
        resolve(data * 2);
    });
}, function(error) {
    console.log('error', error) // 走到这里来
    return error * 2; // return 返回这个基本值表示走下一个then的成功回调
}).then(function(data) {
    console.log('success', data); // 走到这里 success 200
}, function(error) {
    console.log('error', error);
});
  • 在then中(完成回调或拒绝回调)throw一个Error, 或者throw一个 promise,会走到下一个then中的rejected回调; 如果throw一个Promise这个Promise不会被展开,而是原模原样传递给rejected回调函数
new Promise(function(resolve, reject) {
    resolve(100);
}).then(function(data) {
    throw 2
}).then(function(data) {
    console.log('success', data);
}, function(error) {
    console.log('error', error); // 走到这里 error 2
});

new Promise(function(resolve, reject) {
    resolve(100);
}).then(function(data) {
    throw new Promise(function(resolve, reject) {
        resolve(data * 2);
    });
}).then(function(data) {
    console.log('success', data);
}, function(error) {
    console.log('error', error); // 走到这里 error Promise {200}; 这里error就是被上层throw的Promise对象
});

5.Promise的拒绝捕获

  • Promise将程序执行的异常也处理成异步的,走reject逻辑
  • rejected回调也会返回一个promise
new Promise(function(resolve, reject) {
    throw TypeError('type is not support')
}).then(function(data) {
    console.log(data);
}, function(error) {
    console.log('error:', error)// 走到这里 error, TypeError: type is not support
}).then(function(data) {
    console.log('here', data) // 走到这里 here undefined, 因为上一个rejected回调没有拒绝,默认走resolved回调; 没有显示return一个值,采用默认的undefined
})
  • 可以用catch而不是reject回调来捕获这个拒绝
new Promise(function(resolve, reject) {
    reject('type is not support')
}).catch(function(data) {
    console.log('catch', data) // 走到这里 catch type is not support
})
  • catch和reject回调可以共存,捕获才去就近原则
new Promise(function(resolve, reject) {
    reject('type is not support')
}).then(function(data) {
    console.log('success', data);
}, function(error) {
    console.log('error', error); // 走到这里不走catch; error type is not support
}).catch(function(data) {
    console.log('catch', data);
})

new Promise(function(resolve, reject) {
    reject('type is not support')
}).catch(function(data) {
    console.log('catch', data); // 走到这里 catch type is not support
}).then(function(data) {
    console.log('success', data); // 走到这了 success undefined 前一个catch默认使用return undefined
}, function(error) {
    console.log('error', error);
})

6.Promise.resolve(value)将value封装并 返回一个Promise对象

Promise.resolve(value)是下列代码的简写

new Promise(function(resolve){
    resolve(value)
});
  • 如果value不是promise也不是thenable, 返回以这个value值决议的promise对象(resolved回调)
Promise.resolve({ a: 1 }).then(function(data) {
    console.log(data)
});
// {a:1}
  • 如果value是一个thenable,决议的结果取决于这个对象的then方法
var thenable = {
    then: function(resolve) {
        resolve("Resolving");
        throw new TypeError("Throwing");
    }
};

var p3 = Promise.resolve(thenable);
p3.then(function(v) {
    console.log(v); // 输出"Resolving"
}, function(e) {
    // 不会被调用
});
  • value是一个promise, 会对这个promise进行展开;最终的决议结果取决于最里层promise的决议结果
var p1 = Promise.resolve('p1');
var p2 = Promise.resolve(p1);
var p = Promise.resolve(p2);
console.log(p === p1); // true
p.then(function(data) {
    console.log(data); // 'p1'
})

var p1 = Promise.reject('p1');
var p2 = Promise.resolve(p1);
var p = Promise.resolve(p2);
p.then(function(data) {
    console.log(data);
}, function(error) {
    console.log('error', error);// 走到这里 error p1
})

7.Promise.reject(reason)返回一个带有拒绝理由reason的promise

  • Promise.reject是以下代码的简写
new Promise(function(resolve, reject) {
    reject(reason);
});
  • 如果reason是一个Promise, Promise.reject不对reason进行展开,而是以把这个promise的值作为reason传递下去
var p1 = Promise.reject('p1');
var p2 = Promise.reject(p1);
var p = Promise.resolve(p2);
console.log(p === p1); // false
console.log(p === p2); // true
console.log(p1 === p2);//false
p.then(function(data) {
    console.log(data);
}, function(error) {
    console.log('error', error); // 走到这里 error 是Promise p1 不是字符串"p1"
})

8. Promise中的静态方法 Promise.race 和Promise.all

  • Promise.all 接受一个iterable对象,并返回一个promise对象
  • Iterable 中所有的promise都完成了,这个Promise才算完成;返回结果为数组依次对应每个promise完成的结果
  • Iterable中只要有一个失败了,就算失败,失败原因是第一个失败的promise的原因
  • 如果iterable是空数组,立刻决议返回[]

下面列出了Promise.all的源代码实现:

Promise.all = function(iterable) {
    return new Promise(function(resolve, reject) {
        if (typeof iterable !== 'object' && typeof iterable[Symbol.iterator] !== 'function') {
            reject('type error');
        } else if (iterable.length === 0) {
            resolve([]);
        } else {
            let ans = [];
            let len = 0;
            for (let i = 0; i < iterable.length; i++) { // 注意使用let来声明块作用域,闭包!!!
                Promise.resolve(iterable[i]).then(function(data) {
                    len++; // 使用len来追踪获取到了多少个结果; 不能使用ans.length来判断 因为ans[i]的方式会创建稀疏数组导致ans.length不能用来决议的promise的个数
                    ans[i] = data; // 必须使用下标复制 因为不知道谁先到 如果使用ans.push(data)不能保证结果的顺序
                    if (len === iterable.length) {
                        resolve(ans);
                    }
                }).catch(function(error) {
                    reject(error);
                });
            }
        }
    });
}

var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
    setTimeout(resolve, 300, 'foo');
});

var p4 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, 'bar');
});
Promise.all([p1, p2, p3, p4]).then(values => {
    console.log(values); // [3, 1337, "foo", "bar"] 
});
  • Promise.race 接受一个iterable对象,一旦其中的一个promise 决议就立刻决议
  • 如果传入空数组永远不决议!区别于Promise.all

下面是Promise.race的实现

Promise.race = function(iterable) {
    return new Promise(function(resolve, reject) {
        if (typeof iterable !== 'object' && typeof iterable[Symbol.iterator] !== 'function') {
            reject('type error');
        } else if (iterable.length !== 0) {
            for (let i = 0; i < iterable.length; i++) {
                Promise.resolve(iterable[i]).then(function(data) {
                    resolve(data);
                }).catch(function(error) {
                    reject(error);
                });
            }
        }
    });
}

9.Promise.finally的实现

Promise.prototype.finally = function(cb) {
    return this.then(function(data) {
        return Promise.resolve(cb()).then(function() {
            return data;
        });
    }, function(error) {
        return Promise.resolve(cb()).then(function() {
            throw error;
        });
    });
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant