javascript

使用promises

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promisess

一个Promise是一个对象,代表一个异步操作最终的成功或失败。由于大部分人是已经创建的promises的消费者,这个指引将先解释如何使用返回(创建好的)promise,然后再解释如何创建。

本质上,一个promise是一个异步函数返回的对象,你可以attach回调给这个对象,而不是传递callback函数给异步函数。

想象一个函数,createAudioFileAsync(), 它接收参数是一个配置记录和一个成功的回调函数,一个失败的回调函数,然后异步生成一个声音文件。

它的实现是这样的:

function successCallback(result) {console.log("Audio file ready at URL: " + result);
}
​
function failureCallback(error) {console.error("Error generating audio file: " + error);
}
​
createAudioFileAsync(audioSettings, successCallback, failureCallback);

然而现代语言是返回一个promise,然后你可以attach你的callback.

createAudioFileAsync用promise重写,它就会是如下简单:

createAudioFileAsync(audioSettings).then(successCallback, failureCallback);

它是下面的简写:

const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);

上面就是个异步函数调用,下面逐一介绍它的优点。

Guarantees保证

不象老式的传递回调函数,promise的下面几个保证:

  1. 在当前运行JavaScript事件循环的完成之前,永远不会调用回调。

  2. callback通过then来添加,即使是在异步操作完成后(成功或失败),callback也保证会被调用,如前面的例子。

  3. 通过多次调用then来添加多个callback,每个callback会按顺序一个一个地调用。

可以使用chainning是使用promise的最大好处。

Chainning调用链

一个常用的事例是多个异步调用需要一个接一个地调用,后面的操作开始执行基于前面操作返回的结果。 这种我们可以通过promiss chain来完成。

这个魔术的原理是then返回一个新的promise,这是与原来不同的地方。

const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);

也可以写成

const promise2 = doSomething().then(successCallback, failureCallback);  

promise2代表不仅是doSomething完成了,同样代表successCallback或failureCallback的完成,promise2可以是加外一个异步函数返回的promise. 这就是,任何添加在promise2之后的callback都会排在由successCallback or failureCallback返回的promise之后。

基本上,每个promise代表chain上的另外一个异步的完成。

在过去,连续执行几个异步操作会导致经典的回调金字塔:

doSomething(function(result) {doSomethingElse(result, function(newResult) {doThirdThing(newResult, function(finalResult) {console.log('Got the final result: ' + finalResult);}, failureCallback);}, failureCallback);
}, failureCallback);

现代的promise chain

doSomething()
.then(function(result) {return doSomethingElse(result);
})
.then(function(newResult) {return doThirdThing(newResult);
})
.then(function(finalResult) {console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);

then的参数是可选的,而catch(failureCallback)then(null, failureCallback)的简写。

可以用lambda表达式.箭头函数

doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);

重要: 必须返回结果,否则其它callbacks获取不到前一个promise的结果。 (with arrow functions () => x is short for () => { return x; }).

一个具体的promise chain:

new Promise(function(resolve, reject) {setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) { // (**)alert(result); // 1return result * 2;
}).then(function(result) { // (***)alert(result); // 2return result * 2;
}).then(function(result) {alert(result); // 4return result * 2;
});

分开调then的经典错误,下面是不会链式传递结果。

let promise = new Promise(function(resolve, reject) {setTimeout(() => resolve(1), 1000);
});
​
promise.then(function(result) {alert(result); // 1return result * 2;
});
​
promise.then(function(result) {alert(result); // 1return result * 2;
});
​
promise.then(function(result) {alert(result); // 1return result * 2;
});

上面直接返回结果,下面返回的是promise

new Promise(function(resolve, reject) {setTimeout(() => resolve(1), 1000);
}).then(function(result) {alert(result); // 1return new Promise((resolve, reject) => { // (*)setTimeout(() => resolve(result * 2), 1000);});
}).then(function(result) { // (**)alert(result); // 2return new Promise((resolve, reject) => {setTimeout(() => resolve(result * 2), 1000);});
}).then(function(result) {alert(result); // 4
});

具体看 https://javascript.info/promise-chaining

Chaining after a catch

用catch处理chain上失败的情况

new Promise((resolve, reject) => {console.log('Initial');//run
​resolve();
})
.then(() => {throw new Error('Something failed');console.log('Do this');//not run
})
.catch(() => {console.error('Do that');//run
})
.then(() => {console.log('Do this, no matter what happened before');//run
});

输出如下:

Initial
Do that
Do this, no matter what happened before

错误传播Error propagation

你可能还记得,在之前末日金字塔(pyramid of doom)有三次失败回调,而在promise chain的末端,只有一次:

doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => console.log(`Got the final result: ${finalResult}`))
.catch(failureCallback);

如果链上有错误,浏览器就会往链下面 找 .catch() or onRejected

Promises通过捕获所有错误,甚至抛出异常和编程错误,解决了回调金字塔的一个基本缺陷。这对于异步操作的功能组合至关重要。

Promise rejection events

当promise被 rejected时,下面两个event中的一个会发送到全局。(通常是window,或者web worker或者其它基于web worker的interface)

rejectionhandled

reject被处理后

unhandledrejection

reject未被处理

web开发者要学习下,我用nodejs跳过先。

为老的callback api封闭promise

例如旧的

setTimeout(() => saySomething("10 seconds passed"), 10*1000);

用promise

const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
​
wait(10*1000).then(() => saySomething("10 seconds")).catch(failureCallback);

组合Composition

Promise.all()等所有的异步操作并行执行完毕。

Promise.all([func1(), func2(), func3()])
.then(([result1, result2, result3]) => { /* use result1, result2 and result3 */ });

顺序组合

[func1, func2, func3].reduce((p, f) => p.then(f), Promise.resolve())
.then(result3 => { /* use result3 */ });

与下面相等

Promise.resolve().then(func1).then(func2).then(func3);

javascript promises的使用相关推荐

  1. 初识JavaScript Promises

    JavaScript有很多槽点,嵌套回调怕是千夫所指. 很久之前,我一直使用async来处理JavaScript异步编程中的嵌套回调问题.当然我也大概的了解过一些其它旨在解决这些问题的类库,诸如Eve ...

  2. JavaScript Promises

    上篇文章介绍了JavaScript异步机制,请看这里. JavaScript异步机制带来的问题 JavaScript异步机制的主要目的是处理非阻塞,在交互的过程中,会需要一些IO操作(比如Ajax请求 ...

  3. [转]JavaScript/Node.JS 中的 Promises

    JavaScript Promises 初体验 Promise 是什么? Promise 对象用来进行延迟(deferred) 和 异步(asynchronous) 计算. 一个 Promise 处于 ...

  4. JavaScript中的HTTP GET请求?

    我需要在JavaScript中执行HTTP GET请求. 最好的方法是什么? 我需要在Mac OS X破折号小部件中执行此操作. #1楼 上面有很多很棒的建议,但不是很可重用,并且经常被DOM废话和其 ...

  5. javascript闭包_通过邮寄包裹解释JavaScript闭包

    javascript闭包 by Kevin Kononenko 凯文·科诺年科(Kevin Kononenko) 通过邮寄包裹解释JavaScript闭包 (JavaScript Closures E ...

  6. javascript 应用_如何利用JavaScript的功能使您的应用脱机工作

    javascript 应用 In today's world, connectivity has made us more mobile than ever which (paradoxically) ...

  7. javascript测试_了解有关JavaScript承诺的更多信息:25次测试中从零到英雄

    javascript测试 by Andrea Koutifaris 由Andrea Koutifaris 了解有关JavaScript承诺的更多信息:25次测试中从零到英雄 (Learn more a ...

  8. JavaScript进阶之路——认识和使用Promise,重构你的Js代码

    2019独角兽企业重金招聘Python工程师标准>>>  一 .初识Promise 1.什么是promise? Promise可能大家都不陌生,因为Promise规范已经出来好一段时 ...

  9. 程序员必须掌握的 12 个 JavaScript 技能!

    本文论述的12个概念,对于 JavaScript 开发者来说都是非常重要的. 作者 | Nick Scialli 译者 | 谭开朗 责编 | 屠敏 出品 | CSDN(ID:CSDNNews) 以下为 ...

最新文章

  1. 活动报名 | MSRA卢帅:自动化代码审查过程的研究
  2. grid - 使用相同的名称命名网格线和设置网格项目位置
  3. 使用SQL DTS功能实现从DB/2向SQL Server传输数据
  4. 测试oracle删除干净,彻底卸载Oracle
  5. 【Win32汇编】__declspec(naked)裸函数
  6. hydra mysql 爆破_Hydra(爆破神器)使用方法
  7. 将某字符串切割成阵列并排序列出
  8. easyui table 如何只展示一条_如何使用MySQL,这些操作你得明白!
  9. 实验一 Linux开发环境的配置 20145213祁玮 20145222黄亚奇
  10. 泛微OA系统远程命令执行漏洞
  11. 【软件与系统安全】笔记与期末复习
  12. JVM 内存分析神器 MAT: Shallow Heap Vs Retained Heap 你理解的对吗?
  13. Java UTC时间戳
  14. I帧和IDR帧区别(转载)
  15. 利用CSS设置文字的阴影效果
  16. SQL 中GUID的使用
  17. Flutter 新一代图形渲染器 Impeller
  18. Office 365导出PDF带备注页
  19. Centos7学习——echo命令
  20. ES进阶之路二(ES7-ES12)

热门文章

  1. 走进波分 -- 05.波分站点与组网类型
  2. Mac系统下查看鼠标所在点的RGB值--数码测色计
  3. 爬虫:Beautiful Soup
  4. python做并行计算_python做并行计算可以吗
  5. SpringMVC: 前端控制器
  6. Ubuntu下minicom的安装与使用
  7. 八进制转为二进制算法
  8. 拼题A 2021 跨年挑战赛_7-4 相生相克 (15分)
  9. 14 Redis 保存时间序列数据
  10. android 介绍