首页 文章 精选 留言 我的

精选列表

搜索[VMware替代],共10000篇文章
优秀的个人博客,低调大师

CloudLinux 发布 AlmaLinux Beta,社区驱动的 CentOS 替代品

CloudLinux 宣布正式推出 AlmaLinux Beta版本。该团队表示,他们收集了社区的反馈意见,并根据用户对企业级 Linux 发行版的期望构建了这一新的测试版本。AlmaLinux 是RHEL 8 的一个完全免费的 1:1 二进制兼容的分支版本,它受到社区的启发,并由 CloudLinux 背后的工程师和人才打造。 下载地址:https://repo.almalinux.org/almalinux/8.3-beta/isos/x86_64/ CloudLinux方面指出,随着Beta 版本部署,其希望社区能够参与进来,并提供反馈。他们的目标是建立一个完全来自社区贡献和反馈的 Linux 发行版。在 AlmaLinux 测试版期间,希望大家能在测试、文档、支持和操作系统的未来发展方向上提供帮助。一起建立一个 Linux 发行版,填补现在不支持的 CentOS 发行版留下的空白。 AlmaLinux Beta还附带了自己的 bug tracker。注册用户可以提交错误报告,工程团队将对这些报告进行审核和优先处理。 AlmaLinux 8.3 Beta 安装说明 共有三个安装 ISO 映像: AlmaLinux-8.3-beta-1-x86_64-boot.iso(在新窗口中打开)-单个网络安装 CD 映像,可通过 Internet 下载软件包。 AlmaLinux-8.3-beta-1-x86_64-minimal.iso(在新窗口中打开)-最小的自包含 DVD 映像,可以离线安装。 AlmaLinux-8.3-beta-1-x86_64-dvd1.iso(在新窗口中打开)-完整的安装 DVD 映像,其中包含大多数 AlmaLinux 软件包。除非用户需要在无法访问互联网的计算机上设置和使用 AlmaLinux,否则不建议使用。 下载首选的 ISO 映像并验证其校验和。这是 GNU/Linux 的示例: # download and import the AlmaLinux public key $ wget https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux $ gpg --import RPM-GPG-KEY-AlmaLinux # download a checksums list $ wget https://repo.almalinux.org/almalinux/8.3-beta/isos/x86_64/CHECKSUM # verify the checksums list, we are looking for “Good signature” $ gpg --verify CHECKSUM gpg: Signature made Thu 28 Jan 2021 11:39:12 PM MSK gpg: using RSA key 51D6647EC21AD6EA gpg: Good signature from "AlmaLinux <packager@almalinux.org>" [unknown] gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. Primary key fingerprint: 5E9B 8F56 17B5 066C E920 57C3 488F CF7C 3ABB 34F8 Subkey fingerprint: E53C F5EF 91CE B0AD 1812 ECB8 51D6 647E C21A D6EA # download the network install ISO $ wget https://repo.almalinux.org/almalinux/8.3-beta/isos/x86_64/AlmaLinux-8.3-beta-1-x86_64-boot.iso # calculate the downloaded ISO SHA256 checksum $ sha256sum AlmaLinux-8.3-beta-1-x86_64-boot.iso d15be406f417e81382b46a54d87dff01c8ca770c847c18703f19146587b61a1f AlmaLinux-8.3-beta-1-x86_64-boot.iso # compare it with expected checksum, it should be the same $ cat CHECKSUM | grep -E 'SHA256.*AlmaLinux-8.3-beta-1-x86_64-boot.iso' SHA256 (AlmaLinux-8.3-beta-1-x86_64-boot.iso) = d15be406f417e81382b46a54d87dff01c8ca770c847c18703f19146587b61a1f 如果决定使用该AlmaLinux-8.3-beta-1-x86_64-boot.iso映像,则需要提供此https://repo.almalinux.org/almalinux/8.3-beta/BaseOS/x86_64/kickstart/存储库作为安装源: 如果要安装非最小环境,则需要将 AppStream 存储库添加到其他存储库中:https://repo.almalinux.org/almalinux/8.3-beta/AppStream/x86_64/os/。 如果决定使用AlmaLinux-8.3-beta-1-x86_64-minimal.iso或AlmaLinux-8.3-beta-1-x86_64-dvd1.iso映像,则不需要额外的安装源。 如何设置 USB 密钥以安装 AlmaLinux $ dd if=AlmaLinux-8.3-beta-1-x86_64-boot.iso of=/dev/sdX 已知的问题: libreport/abrt 软件包尚未与 bugs.almalinux.org 错误跟踪器集成,因此用户将不得不手动提交崩溃报告。问题:almbz#2。 在 beta 版本中,“perl:5.30”模块支持不完整,计划在稳定版本中完成。 没有最新的“jmc”和“maven”模块版本。将在以后更新。 “satellite-5-client”模块位于 BaseOS 存储库中,而不是 AppStream 中。问题:almbz#4。 测试版不支持安全启动。问题:almbz#3。 debuginfo 信息库为空,将在测试版发布后的几天内填充。 更新说明:https://wiki.almalinux.org/release-notes/8.3-beta.html 延伸阅读: Lenix 更名,计划于本季度推出以取代 CentOS

优秀的个人博客,低调大师

手把手教你Node使用Promise替代回调函数

async 的本质是一个流程控制。其实在异步编程中,还有一个更为经典的模型,叫做 Promise/Deferred 模型(当然还有更多相关解决方法,比如 eventproxy,co 等,到时候遇到在挖坑) 首先,我们思考一个典型的异步编程模型,考虑这样一个题目:读取一个文件,在控制台输出这个文件内容 var fs = require('fs'); fs.readFile('1.txt', 'utf8', function (err, data) { console.log(data); }); 看起来很简单,再进一步: 读取两个文件,在控制台输出这两个文件内容 var fs = require('fs'); fs.readFile('1.txt', 'utf8', function (err, data) { console.log(data); fs.readFile('2.txt', 'utf8', function (err, data) { console.log(data); }); });//欢迎加入全栈开发交流圈一起学习交流:864305860 要是读取更多的文件呢 var fs = require('fs'); fs.readFile('1.txt', 'utf8', function (err, data) { fs.readFile('2.txt', 'utf8', function (err, data) { fs.readFile('3.txt', 'utf8', function (err, data) { fs.readFile('4.txt', 'utf8', function (err, data) { // ... }); });//欢迎加入全栈开发交流圈一起学习交流:864305860 }); }); 这就是传说中的 callback hell,可以使用 async 来改善这段代码,但是在本例中我们要用 promise/defer 来改善它 promise 基本概念 首先它是一个对象,它和 javascript 普通的对象没什么区别,同时,它也是一种规范,跟异步操作约定了统一的接口,表示一个异步操作的最终结果,以同步的方式来写代码,执行的操作是异步的,但又保证程序执行的顺序是同步的 promise 只有三种状态,未完成,完成 (fulfilled) 和失败 (rejected) promise 的状态可以由未完成转换成完成,或者未完成转换成失败 promise 的状态转换只发生一次 promise 有一个 then 方法,then 方法可以接受 3 个函数作为参数。前两个函数对应 promise 的两种状态 fulfilled, rejected 的回调函数。第三个函数用于处理进度信息 为了理解它,一些重要原理必须记牢:.then() 总是返回一个新的 promise,如下面代码: var promise = readFile() var promise2 = promise.then(readAnotherFile, console.error) 这里 then 的参数 readAnotherFile, console.error 是代表异步操作成功后的动作 onFulfilled 或失败后的动作 OnRejected,也就是说,读取文件成功后执行 readAnotherFile 函数,否则失败打印记录错误。这种实现是两个中只有一种可能 也可以理解为: promiseSomething().then(function (fulfilled) { // 当 promise 状态变成 fulfilled 时,调用此函数 }, function (rejected) { // 当 promise 状态变成 rejected 时,调用此函数 }, function (progress) { // 当返回进度信息时,调用此函数 });//欢迎加入全栈开发交流圈一起学习交流:864305860 Promise 法则有两部分必须分离: then() 总是返回一个新的 promise,每次你调用它,它不管回调做什么,因为 .then() 在回调被调用之前已经给了你一个承诺 promise,回调的行为只影响承诺 promise 的实施,如果回调返回一个值,那么 promise 将使用那个值,如果这个值是一个 promise,返回这个 promise 实施后的值给这个值,如果回调抛出错误,promise 将拒绝错误 被 .then() 返回的 promise 是一个新的 promise ,它不同于那些 .then() 被调用的 promise,promise 长长的链条有时会好些隐藏这个事实,不管如何,每次 .then() 调用都会产生一个新的 promise,这里必须注意的是你真正需要考虑的是你最后调用 .then() 可能代表失败,那么如果你不捕获这种失败,那么容易导致你的错误 exception 消失 来看一个利用 q 来处理这种问题的简单例子: var Q = require('q'); var defer = Q.defer(); /** * 获取初始 promise * @private */ function getInitialPromise() { return defer.promise; }//欢迎加入全栈开发交流圈一起学习交流:864305860 /** * 为 promise 设置三种状态的回调函数 */ getInitialPromise().then(function (success) { console.log(success); }, function (error) { console.log(error); }, function (progress) { console.log(progress); }); defer.notify('in progress'); // 控制台打印 in progress defer.resolve('resolve'); // 控制台打印 resolve defer.reject('reject'); // 没有输出。promise 的状态只能改变一次 promise 的传递 then 方法会返回一个 promise,在下面这个例子中,我们用 outputPromise 指向 then 返回的 promise。 var outputPromise = getInputPromise().then(function (fulfilled) { }, function (rejected) { }); 现在 outputPromise 就变成了受 function(fulfilled) 或者 function(rejected) 控制状态的 promise 了。直白的意思就是:当 function(fulfilled) 或者 function(rejected) 返回一个值,比如一个字符串,数组,对象等等,那么 outputPromise 的状态就会变成 fulfilled。 在下面这个例子中,我们可以看到,当我们把 inputPromise 的状态通过 defer.resovle() 变成 fulfilled 时,控制台输出 fulfilled. 当我们把 inputPromise 的状态通过 defer.reject() 变成 rejected,控制台输出 rejected var Q = require('q'); var defer = Q.defer(); /**//欢迎加入全栈开发交流圈一起学习交流:864305860 * 通过 defer 获得 promise * @private */ function getInputPromise() { return defer.promise; } /** * 当 inputPromise 状态由未完成变成 fulfil 时,调用 function(fulfilled) * 当 inputPromise 状态由未完成变成 rejected 时,调用 function(rejected) * 将 then 返回的 promise 赋给 outputPromise * function(fulfilled) 和 function(rejected) 通过返回字符串将 outputPromise 的状态由 * 未完成改变为 fulfilled * @private *///欢迎加入全栈开发交流圈一起学习交流:864305860 var outputPromise = getInputPromise().then(function (fulfilled) { return 'fulfilled'; }, function (rejected) { return 'rejected'; }); /** * 当 outputPromise 状态由未完成变成 fulfil 时,调用 function(fulfilled),控制台打印 'fulfilled: fulfilled'。 * 当 outputPromise 状态由未完成变成 rejected, 调用 function(rejected), 控制台打印 'rejected: rejected'。 */ outputPromise.then(function (fulfilled) { console.log('fulfilled: ' + fulfilled); }, function (rejected) { console.log('rejected: ' + rejected); }); /**//欢迎加入全栈开发交流圈一起学习交流:864305860 * 将 inputPromise 的状态由未完成变成 rejected */ defer.reject(); // 输出 fulfilled: rejected /** * 将 inputPromise 的状态由未完成变成 fulfilled */ //defer.resolve(); // 输出 fulfilled: fulfilled 当 function(fulfilled) 或者 function(rejected) 抛出异常时,那么 outputPromise 的状态就会变成 rejected var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通过 defer 获得 promise * @private *///欢迎加入全栈开发交流圈一起学习交流:864305860 function getInputPromise() { return defer.promise; } /** * 当 inputPromise 状态由未完成变成 fulfil 时,调用 function(fulfilled) * 当 inputPromise 状态由未完成变成 rejected 时,调用 function(rejected) * 将 then 返回的 promise 赋给 outputPromise * function(fulfilled) 和 function(rejected) 通过抛出异常将 outputPromise 的状态由 * 未完成改变为 reject * @private */ var outputPromise = getInputPromise().then(function (fulfilled) { throw new Error('fulfilled'); }, function (rejected) { throw new Error('rejected'); }); /** * 当 outputPromise 状态由未完成变成 fulfil 时,调用 function(fulfilled)。 * 当 outputPromise 状态由未完成变成 rejected, 调用 function(rejected)。 */ outputPromise.then(function (fulfilled) { console.log('fulfilled: ' + fulfilled); }, function (rejected) { console.log('rejected: ' + rejected); }); /** * 将 inputPromise 的状态由未完成变成 rejected */ defer.reject(); // 控制台打印 rejected [Error:rejected] //欢迎加入全栈开发交流圈一起学习交流:864305860 /** * 将 inputPromise 的状态由未完成变成 fulfilled */ //defer.resolve(); // 控制台打印 rejected [Error:fulfilled] 当 function(fulfilled) 或者 function(rejected) 返回一个 promise 时,outputPromise 就会成为这个新的 promise. 这样做的意义在于聚合结果 (Q.all),管理延时,异常恢复等等 比如说我们想要读取一个文件的内容,然后把这些内容打印出来。可能会写出这样的代码: // 错误的写法 var outputPromise = getInputPromise().then(function (fulfilled) { fs.readFile('test.txt', 'utf8', function (err, data) { return data; });//欢迎加入全栈开发交流圈一起学习交流:864305860 }); 然而这样写是错误的,因为 function(fulfilled) 并没有返回任何值。需要下面的方式: var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通过 defer 获得promise * @private *///欢迎加入全栈开发交流圈一起学习交流:864305860 function getInputPromise() { return defer.promise; } /** * 当 inputPromise 状态由未完成变成 fulfil时,调用 function(fulfilled) * 当 inputPromise 状态由未完成变成 rejected时,调用 function(rejected) * 将 then 返回的 promise 赋给 outputPromise * function(fulfilled) 将新的 promise 赋给 outputPromise * 未完成改变为 reject * @private *///欢迎加入全栈开发交流圈一起学习交流:864305860 var outputPromise = getInputPromise().then(function (fulfilled) { var myDefer = Q.defer(); fs.readFile('test.txt', 'utf8', function (err, data) { if (!err && data) { myDefer.resolve(data); } });//欢迎加入全栈开发交流圈一起学习交流:864305860 return myDefer.promise; }, function (rejected) { throw new Error('rejected'); }); /** * 当 outputPromise 状态由未完成变成 fulfil 时,调用 function(fulfilled),控制台打印 test.txt 文件内容。 * *///欢迎加入全栈开发交流圈一起学习交流:864305860 outputPromise.then(function (fulfilled) { console.log(fulfilled); }, function (rejected) { console.log(rejected); }); /** * 将 inputPromise 的状态由未完成变成 rejected */ //defer.reject(); /** * 将 inputPromise 的状态由未完成变成 fulfilled */ defer.resolve(); // 控制台打印出 test.txt 的内容 方法传递 方法传递有些类似于 Java 中的 try 和 catch。当一个异常没有响应的捕获时,这个异常会接着往下传递 方法传递的含义是当一个状态没有响应的回调函数,就会沿着 then 往下找 没有提供 function(rejected) var outputPromise = getInputPromise().then(function (fulfilled) { }) 如果 inputPromise 的状态由未完成变成 rejected, 此时对 rejected 的处理会由 outputPromise 来完成 var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通过defer获得promise * @private *///欢迎加入全栈开发交流圈一起学习交流:864305860 function getInputPromise() { return defer.promise; } /** * 当 inputPromise 状态由未完成变成 fulfil 时,调用 function(fulfilled) * 当 inputPromise 状态由未完成变成 rejected 时,这个 rejected 会传向 outputPromise */ var outputPromise = getInputPromise().then(function (fulfilled) { return 'fulfilled' });//欢迎加入全栈开发交流圈一起学习交流:864305860 outputPromise.then(function (fulfilled) { console.log('fulfilled: ' + fulfilled); }, function (rejected) { console.log('rejected: ' + rejected); }); /** * 将 inputPromise 的状态由未完成变成 rejected */ defer.reject('inputpromise rejected'); // 控制台打印 rejected: inputpromise rejected /** * 将 inputPromise的状态由未完成变成fulfilled *///欢迎加入全栈开发交流圈一起学习交流:864305860 //defer.resolve(); 没有提供 function(fulfilled) var outputPromise = getInputPromise().then(null, function (rejected) { }) 如果 inputPromise 的状态由未完成变成 fulfilled, 此时对 fulfil 的处理会由 outputPromise 来完成 var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /** * 通过defer获得promise * @private */ function getInputPromise() { return defer.promise; }//欢迎加入全栈开发交流圈一起学习交流:864305860 /** * 当 inputPromise 状态由未完成变成 fulfil时,传递给 outputPromise * 当 inputPromise 状态由未完成变成 rejected时,调用 function(rejected) * function(fulfilled) 将新的 promise 赋给 outputPromise * 未完成改变为 reject * @private */ var outputPromise = getInputPromise().then(null, function (rejected) { return 'rejected'; }); //欢迎加入全栈开发交流圈一起学习交流:864305860 outputPromise.then(function (fulfilled) { console.log('fulfilled: ' + fulfilled); }, function (rejected) { console.log('rejected: ' + rejected); }); /** * 将 inputPromise 的状态由未完成变成 rejected */ // defer.reject('inputpromise rejected'); /** * 将 inputPromise 的状态由未完成变成fulfilled */ defer.resolve('inputpromise fulfilled'); // 控制台打印fulfilled: inputpromise fulfilled 可以使用 fail(function(error)) 来专门针对错误处理,而不是使用 then(null,function(error)) var outputPromise = getInputPromise().fail(function (error) { }) 看这个例子: var Q = require('q'); var fs = require('fs'); var defer = Q.defer(); /**//欢迎加入全栈开发交流圈一起学习交流:864305860 * 通过defer获得promise * @private */ function getInputPromise() { return defer.promise; } /** * 当 inputPromise 状态由未完成变成 fulfil 时,调用 then(function(fulfilled)) * 当 inputPromise 状态由未完成变成 rejected 时,调用 fail(function(error)) * function(fulfilled) 将新的 promise 赋给 outputPromise * 未完成改变为reject * @private */ var outputPromise = getInputPromise().then(function (fulfilled) { return fulfilled; }).fail(function (error) { console.log('fail: ' + error); });//欢迎加入全栈开发交流圈一起学习交流:864305860 /** * 将 inputPromise 的状态由未完成变成 rejected */ defer.reject('inputpromise rejected');// 控制台打印 fail: inputpromise rejected /** * 将 inputPromise 的状态由未完成变成 fulfilled */ //defer.resolve('inputpromise fulfilled'); 可以使用 progress(function (progress)) 来专门针对进度信息进行处理,而不是使用 then(function (success) { }, function (error) { }, function (progress) { }) var Q = require('q'); var defer = Q.defer(); /** * 获取初始 promise * @private */ function getInitialPromise() { return defer.promise; } /**//欢迎加入全栈开发交流圈一起学习交流:864305860 * 为 promise 设置 progress 信息处理函数 */ var outputPromise = getInitialPromise().then(function (success) { }).progress(function (progress) { console.log(progress); }); defer.notify(1); defer.notify(2); // 控制台打印 1,2 promise 链 promise 链提供了一种让函数顺序执行的方法 函数顺序执行是很重要的一个功能。比如知道用户名,需要根据用户名从数据库中找到相应的用户,然后将用户信息传给下一个函数进行处理 var Q = require('q'); var defer = Q.defer(); // 一个模拟数据库 var users = [{ 'name': 'andrew', 'passwd': 'password' }]; function getUsername() { return defer.promise; } function getUser(username) { var user; users.forEach(function (element) { if (element.name === username) { user = element; } });//欢迎加入全栈开发交流圈一起学习交流:864305860 return user; } // promise 链 getUsername().then(function (username) { return getUser(username); }).then(function (user) { console.log(user); }); defer.resolve('andrew'); 我们通过两个 then 达到让函数顺序执行的目的。 then 的数量其实是没有限制的。当然,then 的数量过多,要手动把他们链接起来是很麻烦的。比如 foo(initialVal).then(bar).then(baz).then(qux) 这时我们需要用代码来动态制造 promise 链 var funcs = [foo, bar, baz, qux] var result = Q(initialVal) funcs.forEach(function (func) { result = result.then(func) }) return result 当然,我们可以再简洁一点 var funcs = [foo, bar, baz, qux] funcs.reduce(function (pre, current),Q(initialVal){ return pre.then(current) })//欢迎加入全栈开发交流圈一起学习交流:864305860 看一个具体的例子 function foo(result) { console.log(result); return result + result; } // 手动链接 Q('hello').then(foo).then(foo).then(foo); // 控制台输出: hello // hellohello // hellohellohello // 动态链接 var funcs = [foo, foo, foo]; var result = Q('hello'); funcs.forEach(function (func) { result = result.then(func); }); //欢迎加入全栈开发交流圈一起学习交流:864305860 // 精简后的动态链接 funcs.reduce(function (prev, current) { return prev.then(current); }, Q('hello')); 对于 promise 链,最重要的是需要理解为什么这个链能够顺序执行。如果能够理解这点,那么以后自己写 promise 链可以说是轻车熟路啊 promise 组合 回到我们一开始读取文件内容的例子。如果现在让我们把它改写成 promise 链,是不是很简单呢? var Q = require('q'), fs = require('fs'); function printFileContent(fileName) { return function () { var defer = Q.defer(); fs.readFile(fileName, 'utf8', function (err, data) { if (!err && data) { console.log(data); defer.resolve(); } }) return defer.promise; } } //欢迎加入全栈开发交流圈一起学习交流:864305860 // 手动链接 printFileContent('sample01.txt')() .then(printFileContent('sample02.txt')) .then(printFileContent('sample03.txt')) .then(printFileContent('sample04.txt')); // 控制台顺序打印 sample01 到 sample04 的内容 我们会发现为什么要他们顺序执行呢,如果他们能够并行执行不是更好吗? 我们只需要在他们都执行完成之后,得到他们的执行结果就可以了 我们可以通过 Q.all([promise1,promise2...]) 将多个 promise 组合成一个 promise 返回。 注意: 当 all 里面所有的 promise 都 fulfil 时,Q.all 返回的 promise 状态变成 fulfil 当任意一个 promise 被 reject 时,Q.all 返回的 promise 状态立即变成 reject 我们来把上面读取文件内容的例子改成并行执行吧 var Q = require('q'); var fs = require('fs'); /**//欢迎加入全栈开发交流圈一起学习交流:864305860 *读取文件内容 *@private */ function printFileContent(fileName) { // Todo: 这段代码不够简洁。可以使用 Q.denodeify 来简化 var defer = Q.defer(); fs.readFile(fileName, 'utf8', function (err, data) { if (!err && data) { console.log(data); defer.resolve(fileName + ' success '); } else { defer.reject(fileName + ' fail '); } }) //欢迎加入全栈开发交流圈一起学习交流:864305860 return defer.promise; } Q.all([printFileContent('sample01.txt'), printFileContent('sample02.txt'), printFileContent('sample03.txt'), printFileContent('sample04.txt')]) .then(function (success) { console.log(success); }); // 控制台打印各个文件内容 顺序不一定 现在知道 Q.all 会在任意一个 promise 进入 reject 状态后立即进入 reject 状态。如果我们需要等到所有的 promise 都发生状态后(有的 fulfil, 有的 reject),再转换 Q.all 的状态, 这时我们可以使用 Q.allSettled var Q = require('q'), fs = require('fs'); /** *读取文件内容 *@private */ function printFileContent(fileName) { // Todo: 这段代码不够简洁。可以使用Q.denodeify来简化 var defer = Q.defer(); fs.readFile(fileName, 'utf8', function (err, data) { if (!err && data) { console.log(data); defer.resolve(fileName + ' success '); } else { defer.reject(fileName + ' fail '); }//欢迎加入全栈开发交流圈一起学习交流:864305860 }) return defer.promise; } Q.allSettled([printFileContent('nosuchfile.txt'), printFileContent('sample02.txt'), printFileContent('sample03.txt'), printFileContent('sample04.txt')]) .then(function (results) { results.forEach( function (result) { console.log(result.state); } ); });//欢迎加入全栈开发交流圈一起学习交流:864305860 结束 promise 链 通常,对于一个 promise 链,有两种结束的方式。第一种方式是返回最后一个 promise 如 return foo().then(bar); 第二种方式就是通过 done 来结束 promise 链 如 foo().then(bar).done() 为什么需要通过 done 来结束一个 promise 链呢? 如果在我们的链中有错误没有被处理,那么在一个正确结束的 promise 链中,这个没被处理的错误会通过异常抛出 var Q = require('q'); function getPromise(msg, timeout, opt) { var defer = Q.defer(); setTimeout(function () { console.log(msg); if (opt) defer.reject(msg); else defer.resolve(msg); }, timeout); return defer.promise; } //欢迎加入全栈开发交流圈一起学习交流:864305860 /** * 没有用 done() 结束的 promise 链 * 由于 getPromse('2',2000,'opt') 返回 rejected, getPromise('3',1000) 就没有执行 * 然后这个异常并没有任何提醒,是一个潜在的 bug */ getPromise('1', 3000) .then(function () { return getPromise('2', 2000, 'opt') }) .then(function () { return getPromise('3', 1000) }); /** * 用 done() 结束的 promise 链 * 有异常抛出 */ getPromise('1', 3000) .then(function () { return getPromise('2', 2000, 'opt') }) .then(function () { return getPromise('3', 1000) }) .done(); promise 代表一个异步操作的最终结果。主要通过 promise 的 then 方法订阅其最终结果的处理回调函数,和订阅因某原因无法成功获取最终结果的处理回调函数。 A 与 A+ 的不同点 A+ 规范通过术语 thenable 来区分 promise 对象 A+ 定义 onFulfilled/onRejectd 必须是作为函数来调用,而且调用过程必须是异步的 A+ 严格定义了 then 方法链式调用时,onFulfilled/onRejectd 的调用顺序 结语 感谢您的观看,如有不足之处,欢迎批评指正。

优秀的个人博客,低调大师

为什么Android开发者应该使用FlatBuffers替代JSON?

你可能会问,既然我们已经有很标准的JSON以及转换库比如GSON和Jackson,为什么还要使用新的工具呢? 不妨先试一下FlatBuffers,然后你就会发现它比JSON快得多。 FlatBuffers是什么? FlatBuffers是一个高效的跨平台序列化类库,可以在C++、C#、C、Go、Java、JavaScript、PHP和Python中使用。是Google开发的,是为了应用在游戏开发,以及其他注重性能的应用上。 为什么要使用FlatBuffers? 不需要解析/拆包就可以访问序列化数据 — FlatBuffers与其他库不同之处就在于它使用二进制缓冲文件来表示层次数据,这样它们就可以被直接访问而不需解析与拆包,同时还支持数据结构进化(前进、后退兼容性)。 内存高效速度快 — 访问数据时只需要访问内存中的缓冲区。它不需要多余的内存分配(至少在C++是这样,其他语言中可能会有变动)。FlatBuffers还适合配合mmap或数据流使用,只需要缓冲区的一部分存储在内存中。访问时速度接近原结构访问,只有一点延迟(一种虚函数表vtable),是为了允许格式升级以及可选字段。FlatBuffers适合那些花费了大量时间和空间(内存分配)来访问和构建序列化数据的项目,比如游戏以及其他对表现敏感的应用。可以参考这里的基准。 灵活 — 由于有可选字段,你不但有很强的升级和回退兼容性(对于历史悠久的游戏尤其重要,不用为了每个版本升级所有数据),在选择要存储哪些数据以及设计数据结构时也很自由。 轻量的code footprint — FlatBuffers只需要很少量的生成代码,以及一个表示最小依赖的很小的头文件,很容易集成。细节上可以看上面的基准页。 强类型 — 编译时报错,而不需要自己写重复的容易出错的运行时检查。它可以自动生成有用的代码。 使用方便 — 生成的C++代码允许精简访问与构建代码。还有可选的用于实现图表解析、类似JSON的运行时字符串展示等功能的方法。(后者比JSON解析库更快,内存效率更高) 代码跨平台且没有依赖 — C++代码可以运行在任何近代的gcc/clang和VS2010上。同时还有用于测试和范例的构建文件(Android中.mk文件,其他平台是cmake文件)。 都有谁使用FlatBuffers? BobbleApp,印度第一贴图App。我们在BobbleApp中使用FlatBuffers后App的性能明显增强。 Cocos2d-x,第一开源移动游戏引擎,使用FlatBuffers来序列化所有的游戏数据。 Facebook使用FlatBuffers在Android App中进行客户端服务端的沟通。他们写了一篇文章来描述FlatBuffers是如何加速加载内容的。 Google的Fun Propulsion Labs在他们所有的库和游戏中大量使用FlatBuffers。 App性能有多大提高? 解析速度 解析一个20KB的JSON流(这差不多是BobbleApp的返回大小)需要35ms,超过了UI刷新间隔也就是16.6ms。如果解析JSON的话,我们就在滑动时就会因为要从磁盘加载缓存而导致掉帧(视觉上的卡顿)。 解析器初始化 一个JSON解析器需要先构建字段映射再进行解析,这会花100ms到200ms,很明显的拖缓App启动时间。 垃圾回收 在解析JSON时创建了很多小对象,在我们的试验中,解析20kb的JSON流时,要分配大约100kb的瞬时存储,对Java内存回收造成很大压力。 FlatBuffers vs JSON 我尝试使用FlatBuffers和JSON解析4mb的JSON文件。 FlatBuffers花了1-5ms,JSON花了大约2000ms。在使用FlatBuffers期间Android App中没有GC,而在使用JSON时发生了很多次GC。在使用JSON时UI完全卡住,所以真实使用时只能在后台线程进行解析。 如何使用FlatBuffer呢? 我在我的GitHub中写了一个示例,里面手把手教你如何使用FlatBuffer。 ====================================分割线================================ 本文转自d1net(转载)

优秀的个人博客,低调大师

【分布式计算】MapReduce的替代者-Parameter Server

首先还是要声明一下,这个文章是我在入职阿里云1个月以来,对于分布式计算的一点肤浅的认识,可能有些地方不够妥善,还请看官可以指出不足的地方,共同进步。 一.背景 随着互联网的发展,数据量的增大,很多对于数据的处理工作(例如一些推荐系统、广告推送等)都迁移到了云端,也就是分布式计算系统上。衍生了很多牛逼的分布式计算的计算模型,比较著名的就是MapReduce、MPI、BSP等。后来也产生了一些分布式计算系统,大家耳熟能详的Hadoop就是基于MapReduce实现的。 本文的主人公是Parameter Server,其实也不算是新宠了,这个模型已经被提出好几年了,只不过在国内还不是特别热。不过最近一些云服务巨头们开始了对于PS的深入开发和研究。 引用一位算法大神的话简单描述下什么事Parameter Server:总结是一种计算模型SSP+一

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册