新闻中心

欧洲杯体育Try 和 Method 同理-世博体育(中国)登录入口官方网站IOS安卓/通用版/APP官方网站

         发布日期:2024-06-15 09:15    点击次数:179

Bluebird 实战

JavaScript 异步编程

JavaScript 是一门单线程谈话,被等闲的诳骗于浏览器端和页面 DOM 元旧友互。自从 Node.js 横空出世,JavaScript 的限制由浏览器膨大到干事器端,造成了一种通用的缱绻机体式设想谈话。那么,JavaScript 是怎样杀青异步编程的呢?

Callback 和 Callback 地狱

JavaScript 的异步是用 Callback 函数来杀青的。Callback 函数不错接收外部体式传入的参数,然则没认识向外部传值,只可通过下一个 Callback 函数来使用。这使适合逻辑复杂的时辰,Callback 嵌套变得很深。在这种情况下,参数彼此影响,导致 bug 好多。这种嵌套被称为 Callback 地狱。

Promise 和 Bluebird

Promise 是 JavaScript 中处治 Callback 地狱的边幅,也被 ECMAScript 协会承认,固化为 ES6 语法的一部分。Bluebird 是早期 Promise 的一种杀青,它提供了丰富的格式和语法糖,一方面镌汰了 Promise 的使用难度,一方面膨大了 Promise 的功能。下文中所有的格式来自于 Bluebird api 接口。

Promise 基础

Promise 是一个本旨,默示一次操作的后果。和一般操作不同的是,Promise 对象不是及时的,而是在将来的某一技艺,会有复返。咱们知谈,JavaScript 在浏览器中是单线程调用的,然则未必咱们又需要异步操作,举例探望文献,或者是调用 ajax。这时辰,咱们就需要 Promise 了。

以下清单 1 展示了 Promise 创建和使用进程。

率先,new Promise 不错传入两个函数,resolve 和 reject 格式。当 Promise 正确调用复返 resolve,并封装复返用户数据;当调用失败时,调用 reject 格式,并封装失败原因。其次,Promise 的复返值只可在链式格式中调用。

清单 1. 创建 Promise 对象并复返

"use strict";describe("Suite1", function(){let Promise = require("bluebird");it("Promise basic function arch", function(){let promise = new Promise(function(resolve, reject){let returnBody = true;return returnBody?resolve(returnBody):reject(returnBody);});promise.then(function(data){expect(data).toEqual(true);});});});

Promise resolve 和 reject 语法糖

以上创建 Promise 用的是 new 的齐备格式。Bluebird 也提供 resolve 和 reject 的语法糖,不错粗略的创建一个 Promise 对象,如清单二。

清单 2. Promise resolve 和 reject 语法糖的诳骗

it("Promise resolve and reject sugar", function(){let resolvePromise = Promise.resolve(true);let rejectPromise = Promise.resolve(false);resolvePromise.then(function(data){expect(data).toBeTruthy();})rejectPromise.then(function(data){expect(data).toBeFalsy();})});

Then 格式

Then 格式不错说是 Promise 中最基本的格式,它不错接纳两个参数,第一个 onFulfilled handler,第二个 onRejected handler。一般来说这两个皆是函数,在需要忽略恣意一个 handler 的时辰,不错用对象来代替。如清单 3 代码。

清单 3. 忽略 Then 中的完成函数

it("Then function with ignore fulFilled handler", function(){let promise = new Promise(function(resolve, reject){let returnBody = false;return returnBody?resolve(returnBody):reject(returnBody);});promise.then({},function(error){expect(error).toEqual(false);});});

Promise 链

需要真贵的是 Promise.then 格式复返的亦然一个 Promise 对象,它同期也不错被下一个格式衔接。雷同于清单 4 中的伪代码。

清单 4. Promise 链式调用

Promise.then().then().then()

那么在背面的 then 中接纳的对象是什么呢?Promise 中,then 中不错有一个 return 格式,这里的 return 复返的是下一个 then 格式中的参数对象。如清单 5 代码平永诀复返了一个对象,和一个函数。Bluebird 会把复返值转机为 Promise 对象供下一个函数调用。

清单 5. Promise 函数中的复返值

it("Promise chain with return function", function(){let promise = new Promise(function(resolve, reject){let returnBody = true;return returnBody?resolve(returnBody):reject(returnBody);});promise.then(function(data){expect(data).toEqual(true);return {a:1,b:2};}).then(function(data){expect(data.a).toEqual(1);expect(data.b).toEqual(2);return function(){return "string";};}).then(function(func){expect(_.isFunction(func)).toBeTruthy();let string = func();expect(string).toEqual("string");});});

Spread 格式

spread 格式适用于 Promise 对象复返值是数组的时辰。与 then 格式换取,spread 格式复返一个 Promise 对象。如清单 6。

清单 6. Spread 格式的诳骗

it("Spread function basic without Promise.all", function(){let promise = new Promise(function(resolve, reject){let returnBody = [1,2,3];return returnBody?resolve(returnBody):reject(returnBody);});promise.spread(function(data1,data2,data3){expect(data1).toEqual(1);expect(data2).toEqual(2);expect(data3).toEqual(3);});});

或者不错用阐述格式把参数伸开,如清单 7 代码段,这里的 spread 格式和 then 格式的功能换取。

清单 7. Spread 和 Then 的调用

promise.spread(function(...data){expect(data).toEqual([1,2,3]);});promise.then(function(data){expect(data).toEqual([1,2,3]);});

Bind 函数

在 Promise 对象调用的时辰,存在一个险阻文对象,即 this 对象。一般情况下,咱们不成探望到 this 对象,然则 Bind 函数不错匡助咱们 bind 一个 this。这在链式调用传递参数的时辰特地灵验。如清单 8。需要讲明的是,this 对象和 then 函数中的复返值没相联系。

清单 8. Bind 格式的使用

it("Bind function", function(){Promise.bind({a:1}).then(function(){this.b = 2;}).then(function(){this.c = 3;return 6;}).then(function(data){expect(this.a+this.b+this.c).toEqual(data);});});

Promise try 和 method

Promise try 和 Method 皆是粗略创建 Promise 的格式。咱们不错不雅察到,在 then 的 return 格式中,不错复返一个数值,一个数组,以致是一个函数,这些皆不错被阐述成 Promise 对象而被下一次链式调用。

Try 和 Method 同理,不错把含有 error 抛出的或有昔时的复返值的函数,转机为 Promise 对象,粗略之后调用。它俩的不同点是,try 复返的是 Promise 对象,method 复返的是一个函数,函数调用之后是 Promise 对象。如以下清单 9。

清单 9. Promise try 和 method 的区别

it("Error and method functions", function(){Promise.try(function(){throw new Error("this should be error");}).then({}, function(err){expect(err).toEqual(new Error("this should be error"));});Promise.method(function(){return "message";})().then(function(data){//真贵这里的 method 函数复返之后要进行调用再实践 then 格式expect(data).toBe("message");})});

链式调用中的 Promise 函数

Promise 函数有两种:

一种是用来创建 Promise 链的头对象的,举例 resolve 和 reject 格式;另外一种只可在链式调用进程中使用,举例 then,spread 格式。

然则有一种函数,举例 bind,它既能创建头对象,也能在链式进程中调用,既有 Promise.bind(),又有.bind()。Bluebird 提供了多数这么的函数,咱们在背面的容器管束中,不错具体看到。

特地处理

既然 Promise 仅仅一个允诺,那么就有失败的可能,在创建 Promise 对象的时辰就有一个 reject 函数来默示特地;在 then 函数也有 onRejected handler 的处理。

看清单 10,Promise 的处理包含了 onRejected handler 和 catch 函数,当 then 格式中处理了特地之后,在 catch 中拿获不到特地。

清单 10. Then 的 onRejected 格式和 catch 函数

it("Promise with catch handler", function(){let promise = new Promise(function(resolve, reject){let returnBody = false;return returnBody?resolve(true):reject(false);});promise.then({},function(data){expect(data).toBe(false);}).catch(function(e){expect(true).toBe(false);}).finally(function(){expect(true).toBeTruthy();});});

Then 函数中的 OnRejected 和 catch 函数的区别有:

一朝 then 拿获到了特地,catch 函数中就拿获不到特地。catch 函数能拿获到这个 Promise chain 中的特地。then 只可拿获单个 Promise 中的特地。finally 函数保证在这个 Promise 链实践之后皆会被实践,一般用于关闭在 Promise 中的资源。

资源管束

咱们知谈 finally 函数时常用来关闭资源,然则在 Promise 调用复杂时,尤其是多个调用同期进行(举例使用 Promise.all 进行一组调用的时辰)。咱们不好识别哪些需要关闭,这时辰就能用到 Promise.using 函数了。

Promise.using

咱们不错用 disposer 函数把一个 Promise 对象转机成 disposer 对象供 Promise.using 调用。在 disposer 中界说资源关闭逻辑,那么在 Promise.using 调用的进程中,会自动实践 disposer 的资源关闭逻辑。如清单 11,会在 then 格式实践前,打印出 resource closed 字样。

清单 11. Promise using 资源管束

it("Promise using function call", function(){let f = function(){return Promise.resolve(true).disposer(function(){console.log("resource closed");});};Promise.using(f(), function(data){expect(data).toBeTruthy();}).then(function(){console.log("resouce cannot be used");})});

测试函数

在原型链实践进程中,淌若咱们要监测 Promise 的复返气象咱们不错使用测试函数。Bluebird 提供的测试函数有以下四种。

IsFulFilledIsRejectedisPendingisCancelled

合营使用的赢得复返后果和进行诞妄处理的函数有 value 和 reason。如清单 12。

清单 12. 测试函数样例

if(p.isFulFilled()){console.log(p.value());}if(p.isRejected()){console.log(p.reason());}

Promisification

Bluebird 提供了好多格式来匡助咱们把现存的库函数由 Callback 的边幅,转机为 Promise 的边幅,这叫作念 Promise 化。最常见的,举例 Node 中默许提供的 fs 文献操作句柄,咱们不错通过 Promise.promiseifyAll(fs) 的边幅,把 fs 的调用,通过 Promise 复返。

清单 13. Promise 化 Nodejs 中的 fs

"use strict";describe("Suite3", function(){let Promise = require("bluebird");let fs = require("fs");Promise.promisifyAll(fs);//这里 fs 被改写了,增多了 Async 后缀的格式it("Collection usage", function(){fs.readFileAsync('./spec/t2Spec.js', 'utf8').then(function(data){console.log(data);});});});

需要真贵的是,fs 是一个 singleton 对象,不错简略的用 PromiseAll 来封装,调用 fs 的函数时,需要加上一个 Async 的后缀。通过检察 Bluebird 中 Promise 的源码,不错发现 PromiseAll 格式是通过给对象添加格式的边幅来封装对象的原有格式。另外,PromisifyAll 的复返值亦然加工过的对象。

图 1. PromiseAll 转机 Object 华夏有格式

清单 14. 使用 PromisifyAll 格式界说对象

it("PromisifyAll test", function(){let obj = {func1: function(data, callback1, callback2){callback1(null, data + "1");callback2("error", data + "2");}}Promise.promisifyAll(obj);obj.func1Async("alert").then(function(data){expect(data).toBe("alert1");}, function(err){expect(false).toBeTruthy();});});

这里咱们为了测试 PromisifyAll 的旨趣,设想了两个 callback 格式。一般来说,异步实践的函数只消一个 callback 格式。

PromiseAll 中 Then 格式的复返和界说的第一个 callback 格式联系,咱们这里是 Callback1。Then 中的 fulFilled 和 Reject 函数使用的格式只和 func1 中调用的参数相联系,和 callback1 的杀青没相联系。Func1 中,函数必须放在数据传参背面,当作尾参数。callback 格式中的第一个参数是 error 信息。callback1 和 callback2 在 obj 的 func1 中必须按照界说规章调用,举例先实践 callback2(null,data) 再实践 callback1(null, data) 是不被 Bluebird 允许的。

清单 15. 使用 PromisifyAll 格式界说原型链

it("PromiseAll prototype test", function(){function test(){this.ab = "new";}test.prototype.ab = function(param, cb){cb(null, param);}let test2 = Promise.promisifyAll(test.prototype);test2.abAsync("test").then(function(data){expect(data).toBe("test");});});

关于某些库,杀青的时辰是用原型来封装格式,咱们不错使用手动的边幅来使格式 Promise 化。这时辰需要改写原型的称呼,如清单 15 中,用的是 test2 来默示改写后的原型格式。

另外,Promise 默许是在格式上加上 Async 后缀,不错使用 suffix 参数来手动指定后缀名。如清单 16。

清单 16. 指定 Promisify 中的后缀参数

var fs = Promise.promisifyAll(require("fs"), {suffix: "MySuffix"});fs.readFileMySuffix(...).then(...)

容器管束

Promise.all 和 Promise.join

Promise 容器中,最常见的是 Promise.all 格式,标明当所有的 Promise 对象数组中的 Promise 皆完成的时辰,复返 Promise 对象。当有一个 Promise 失败的时辰,实践 then 的 reject 格式,复返第一个诞妄的 Promise 对象施行。

清单 17. Promise all 的使用

it("Promise.all usage", function(){let obj = {func1: function(data, cb){if(data>8){cb("error",data);}else{cb(null, data);}}}Promise.promisifyAll(obj);let promises = [];for(let i = 1; i < 10; ++i){promises.push(obj.func1Async(i));}Promise.all(promises).then(function(){expect(true).toBeFalsy();}, function(){expect(true).toBeTruthy();});});

和 Promise all 格式相同,join 亦然默示当一组数据一齐完成时辰的复返格式。与 all 不同的是,join 一般适用于静态的一组数据,即已知长度的一组 Promise。

Promise.any 和 Promise.some

Promise.any 默示有第一个 Promise 见效实践则实践 then 的完成格式。

清单 18. Promise any 的使用

it("Promise.any usage", function(){let obj = {func1: function(data, cb){if(data <= 3){cb(data, data);}else{cb(null, data);}}}Promise.promisifyAll(obj);let promises = [];for(let i = 1; i < 10; ++i){promises.push(obj.func1Async(i));}Promise.any(promises).then(function(data){expect(data).toBe(4);}, function(err){expect(true).toBeFalsy();});});

Promise.some 和 any 不同的是,不错指定前几个 Promise 见效实践 then 的完成格式。一般和 spread 合营使用。

清单 19. Promise some 的使用

Promise.some([ping("ns1.example.com"),ping("ns2.example.com"),ping("ns3.example.com"),ping("ns4.example.com")], 2).spread(function(first, second) {console.log(first, second);});

Promise.map 和 Promise filter

Promise map 和 filter 不错传入一个迭代器函数并进行处理。和 then 格式相似,不要求在函数中复返 Promise。Bluebird 不错匡助转机 Promise 对象。

如清单 20,map 的迭代器函数中不错赢得 map 中的复返值;而 filter 的迭代器中过滤稳当条目的 Promise(通过 return 格式复返值判断),在 then 函数中处理。

清单 20. Promise map 和 filter 使用

it("Promise map and filter", function(){let f1 = Promise.method(function(){return "f1"});let f2 = Promise.method(function(){return "f2";});Promise.map([f1(),f2()], function(data){console.log(data);//打印出 f1, f2}).then(function(){console.log("done");});Promise.filter([f1(),f2()], function(data, index){return index>0;}).then(function(data){console.log(data);//打印出[ 'f2' ]});});

规章实践

在一组容器中的 Promise 对象实践进程中,像 all 和 map 这么的格式,Promise 对象之间莫得要求同步,淌若热烈要求 Promise 对象之间的实践顺规章,不错取舍规章容器,如图 2 中,规章实践的格式。

图 2. Promise 中非规章实践谦恭序实践的格式分类

限度语

Bluebird 处治了 callback 地狱的问题,它把 callback 格式的调用欧洲杯体育,空洞成 Promise 对象之间的链式调用。Bluebird 提供了多数创建 Promise 对象的格式。况且能把已有的干事封装成 Promise 对象复返类的干事。使之进行异措施用。Bluebird 提供的容器有保证规章实践的和不保证规章实践的两种。本文通过关于 Bluebird 的 api 的解读,匡助读者领会 Bluebird 的使用格式。



 
友情链接:

Powered by 世博体育(中国)登录入口官方网站IOS安卓/通用版/APP官方网站 @2013-2022 RSS地图 HTML地图