资讯专栏INFORMATION COLUMN

《JavaScript Promise迷你书》读书笔记

Aldous / 1892人阅读

摘要:定义是抽象异步处理对象以及对其进行各种操作的组件简言之,使用就是将中异步的方式变换成同步来操作。如果对异步回调函数进行同步调用的话,处理顺序可能会与预期不符,可能带来意料之外的后果。如果想在将来某时刻调用异步回调函数的话,可以使用等异步。

promise定义

Promise是抽象异步处理对象以及对其进行各种操作的组件

简言之,使用Promise就是将javascript中异步的方式变换成同步来操作。Promise则是把类似的异步处理对象和处理规则进行规范化, 并按照采用统一的接口来编写,规定方法之外的写法都会报错。简单的示例:

    var promise = getAsyncPromise("fileA.txt"); //处于Pending状态,既不是resolve也不是reject的状态。是promise对象刚被创建后的初始化状态
    promise.then(function(result){
        // 获取文件内容成功时的处理 成功时状态为onFulfilled
    }).catch(function(error){
        // 获取文件内容失败时的处理 失败时状态为onRejected
    });

其中,thencatch代表函数执行成功和失败的预设操作

构建promise对象,使用new关键字
    var promise = new Promise(function(resolve, reject) {
        // 异步处理
        // 处理结束后、调用resolve 或 reject
    });
对象方法 then
    promise.then(onFulfilled, onRejected); //onFulfilled函数会在promise对象的revolve状态调用,onRejected为在promise对象reject状态下调用
    promise.catch(function());//catch用来代替onRejected抛出错误 
promise对象中内置部分静态方法

Promise.all() Promise.racePromise.resolve(),Promise.reject

创建XHR的promise对象
function getURL(URL) {
return new Promise(function (resolve, reject) {
    var req = new XMLHttpRequest();
    req.open("GET", URL, true);
    req.onload = function () {
        if (req.status === 200) {
            resolve(req.responseText);//传入resolve中的参数会在状态改变的时候,传到then中
        } else {
            reject(new Error(req.statusText));
        }
    };
    req.onerror = function () {
        reject(new Error(req.statusText));
    };
    req.send();
});
}
// 运行示例
var URL = "http://httpbin.org/get";
getURL(URL).then(function onFulfilled(value){
console.log(value);
}).catch(function onRejected(error){
console.error(error);
});
Promise.resolve

作用1. Promise.resolve 是 new Promise(func)的快捷方式,如Promise.resolve(42);new Promise(function(resolve){ resolve(42);});
作用2. 将thenable 对象转换为promise对象。thenable指的是一个具有 .then方法的对象。

Promise.reject
Promise.reject(new Error("出错了"))

等价于

new Promise(function(resolve,reject){
    reject(new Error("出错了"));
});

使用

Promise.reject(new Error("BOOM!")).catch(function(error){
    console.error(error);
});
promise对象立刻进入resolve状态
var promise = new Promise(function (resolve){
    console.log("inner promise"); // 1
    resolve(42);
});
promise.then(function(value){
    console.log(value); // 3
});
console.log("outer promise"); // 2

输出结果为 1,2,3; 即使resolve立即执行,得出的结果也在下一个时间环里,需要等到下一周期才能执行

1.绝对不能对异步回调函数(即使在数据已经就绪)进行同步调用。
2.如果对异步回调函数进行同步调用的话,处理顺序可能会与预期不符,可能带来意料之外的后果。
3.对异步回调函数进行同步调用,还可能导致栈溢出或异常处理错乱等问题。
4.如果想在将来某时刻调用异步回调函数的话,可以使用 setTimeout 等异步API。

对比三段代码:

第一段:直接判断文件是否加载完成

function onReady(fn) {
    var readyState = document.readyState;
    if (readyState === "interactive" || readyState === "complete") {
        fn();
    } else {
        window.addEventListener("DOMContentLoaded", fn);
    }
}
onReady(function () {
    console.log("DOM fully loaded and parsed");
});
console.log("==Starting==");

第二段:使用setTimeout转同步为异步操作

function onReady(fn) {
    var readyState = document.readyState;
    if (readyState === "interactive" || readyState === "complete") {
        setTimeout(fn, 0); //使用setTimeout转化同步函数为异步函数
    } else {
        window.addEventListener("DOMContentLoaded", fn);
    }
}
onReady(function () {
    console.log("DOM fully loaded and parsed");
});
console.log("==Starting==");

第三段:使用promise的resolve将统一为异步的方式,减少判断

    function onReadyPromise() {
    return new Promise(function (resolve, reject) {
        var readyState = document.readyState;
        if (readyState === "interactive" || readyState === "complete") {
            resolve();
        } else {
            window.addEventListener("DOMContentLoaded", resolve);
        }
    });
}
onReadyPromise().then(function () {
    console.log("DOM fully loaded and parsed");
});
console.log("==Starting==");

关于传递参数promise的写法

function doubleUp(value) {
    return value * 2;
}
function increment(value) {
    return value + 1;
}
function output(value) {
    console.log(value);// => (1 + 1) * 2
}

var promise = Promise.resolve(1);//构造一个返回参数为1的promise对象
promise
    .then(increment) //此时increment函数中传的vaule值为1
    .then(doubleUp) //此时doubleUp函数中传的vaule值为2
    .then(output) //此时doubleUp函数中传的vaule值为 4
    .catch(function(error){
        // promise chain中出现异常的时候会被调用
        console.error(error);
    });

Promise.resolvePromise.reject会对函数中return返回的值进行包装,最终then返回的结果都是新创建的promise对象

Promise.all的使用

function getURL(URL) {
    return new Promise(function (resolve, reject) {
        var req = new XMLHttpRequest();
        req.open("GET", URL, true);
        req.onload = function () {
            if (req.status === 200) {
                resolve(req.responseText);
            } else {
                reject(new Error(req.statusText));
            }
        };
        req.onerror = function () {
            reject(new Error(req.statusText));
        };
        req.send();
    });
}
var request = {
        comment: function getComment() {
            return getURL("http://azu.github.io/promises-book/json/comment.json").then(JSON.parse);
        },
        people: function getPeople() {
            return getURL("http://azu.github.io/promises-book/json/people.json").then(JSON.parse);
        }
    };
function main() {
    return Promise.all([request.comment(), request.people()]);
}
// 运行示例
main().then(function (value) {
    console.log(value);
}).catch(function(error){
    console.log(error);
});

证明Promise.all的promise数组是同时开始执行的

// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
var startDate = Date.now();
// 所有promise变为resolve后程序退出
Promise.all([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64),
    timerPromisefy(128)
]).then(function (values) {
    console.log(Date.now() - startDate + "ms");
    // 約128ms
    console.log(values);    // [1,32,64,128]
});

Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理

// `delay`毫秒后执行resolve
function timerPromisefy(delay) {
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
// 任何一个promise变为resolve或reject 的话程序就停止运行
Promise.race([
    timerPromisefy(1),
    timerPromisefy(32),
    timerPromisefy(64),
    timerPromisefy(128)
]).then(function (value) {
    console.log(value);    // => 1
});


//代码第二段 
var winnerPromise = new Promise(function (resolve) {
        setTimeout(function () {
            console.log("this is winner");
            resolve("this is winner");
        }, 4);
    });
var loserPromise = new Promise(function (resolve) {
        setTimeout(function () {
            console.log("this is loser");
            resolve("this is loser");
        }, 1000);
    });
// 第一个promise变为resolve后程序停止
Promise.race([winnerPromise, loserPromise]).then(function (value) {
    console.log(value);    // => "this is winner"
});

不能进行错误处理的onRejected

function throwError(value) {
    // 抛出异常
    throw new Error(value);
}
// <1> onRejected不会被调用
function badMain(onRejected) {
    return Promise.resolve(42).then(throwError, onRejected);
}
// <2> 有异常发生时onRejected会被调用
function goodMain(onRejected) {
    return Promise.resolve(42).then(throwError).catch(onRejected);
}
// 运行示例
badMain(function(){
    console.log("BAD");
});
goodMain(function(){
    console.log("GOOD");
});

说明:上面代码中<1>中throwError 抛出了异常,onRejected 指定的函数也不会被调用

.then 和 .catch 都会创建并返回一个 新的 promise对象。 Promise实际上每次在方法链中增加一次处理的时候所操作的都不是完全相同的promise对象。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78607.html

相关文章

  • JS笔记

    摘要:从最开始的到封装后的都在试图解决异步编程过程中的问题。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。异步编程入门的全称是前端经典面试题从输入到页面加载发生了什么这是一篇开发的科普类文章,涉及到优化等多个方面。 TypeScript 入门教程 从 JavaScript 程序员的角度总结思考,循序渐进的理解 TypeScript。 网络基础知识之 HTTP 协议 详细介绍 HTT...

    rottengeek 评论0 收藏0
  • javascript正则迷你-笔记

    showImg(https://segmentfault.com/img/bVbfGSV?w=719&h=718); showImg(https://segmentfault.com/img/bVbfGTc?w=801&h=552); showImg(https://segmentfault.com/img/bVbfGTq?w=1017&h=501);

    LinkedME2016 评论0 收藏0
  • JavaScript正则表达式迷你-笔记

    摘要:比如正则表示匹配这样一个字符串第一个字符是,接下来是到个字符,最后是字符。其实现的方式是使用字符组。具体形式如下,其中和是子模式,用管道符分隔,表示其中任何之一。 贪婪模式: 在使用修饰匹配次数的特殊符号时,有几种表示方法可以使同一个表达式能够匹配不同的次数,比如:{m,n}, {m,}, ?, *, +,具体匹配的次数随被匹配的字符串而定。这种重复匹配不定次数的表达式在匹配过程中,总...

    widuu 评论0 收藏0
  • 笔记】你不知道的JS读笔记——Promise

    摘要:写在前面这一章的顺序对于未接触过使用过的童鞋而言略抽象了,前边几章主要为了说明和之前的异步方式相比有什么优势和它能解决什么问题,后边才详解的设计和各种场景下如何使用。建议先了解和简单使用过后再阅读,效果更佳。 写在前面:Promise这一章的顺序对于未接触过使用过Promise的童鞋而言略抽象了,前边几章主要为了说明Promise和之前的异步方式相比有什么优势和它能解决什么问题,后边才...

    mumumu 评论0 收藏0
  • 一道笔试题引发的Promise笔记

    摘要:对象是一个返回值的代理,这个返回值在对象创建时未必已知。这使得异步方法可以像同步方法那样返回值异步方法会返回一个包含了原返回值的对象来替代原返回值。 前言 近来参加校招笔试,发现有好几道关于Promise的题目。然而我都没有了解过。所以,这篇文章以网易笔试的一道题开始,记录关于Promise的那些事。文章地址:http://lsxj615.com/2016/08/04... 笔试题 c...

    _Suqin 评论0 收藏0

发表评论

0条评论

Aldous

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<