传统的基于 callback 的实现形式:
function loadScript(src, callback) { let script = document.createElement('script'); script.src = src; script.onload = () => callback(null, script); script.onerror = () => callback(new Error(`Script load error for ${src}`)); document.head.append(script);}
如果应用 promise,则防止了回调函数的应用。
新函数 loadScript 不须要回调。 相同,它将创立并返回一个 Promise 对象,该对象在加载实现时解析。 内部代码能够应用 .then 向其增加处理程序(订阅函数):
function loadScript(src) { return new Promise(function(resolve, reject) { let script = document.createElement('script'); script.src = src; script.onload = () => resolve(script); script.onerror = () => reject(new Error(`Script load error for ${src}`)); document.head.append(script); });}
如何应用这个 loadScript
:
let promise = loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js");promise.then( script => alert(`${script.src} is loaded!`), error => alert(`Error: ${error.message}`));promise.then(script => alert('Another handler...'));
应用 Promise 编写代码,容许咱们依照天然程序做事。 首先,咱们运行 loadScript(script),而后咱们应用相似自然语言的语法 then,编写如何处理结果。
反观 callback 解决方案,调用 loadScript(script, callback) 时,咱们必须有一个回调函数可供使用。 换句话说,咱们必须在调用 loadScript 之前晓得如何处理结果。
咱们能够依据须要屡次调用 .then 。 每次,咱们都会在“订阅列表”中增加一个新的“粉丝”,一个新的订阅性能。而 Callback 的解决方案,只反对单个 Callback.
咱们如果屡次在 executor 里调用 resolve,会产生什么情景?
比方思考上述代码:
let promise = new Promise(function(resolve, reject) { resolve(1); setTimeout(() => resolve(2), 1000);});promise.then(alert);
答案是 1.
第二次调用resolve被疏忽,因为只思考第一次reject/resolve调用。 进一步的调用将被疏忽。
promise 有很多妙用,比方用来实现 delay 函数。
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms));}delay(3000).then(() => alert('runs after 3 seconds'));
delay 的 executor 里,三秒之后再调用 resolve,因此实现了 delay 成果。
请留神,在这个工作中,resolve
的写法,含意是 resolve 被调用,没有参数。 咱们不会从提早中返回任何值,只是确保提早。
上面是用 promise 实现的一个特效:
<!DOCTYPE html><html><head> <meta charset="utf-8"> <style> .message-ball { font-size: 20px; line-height: 200px; text-align: center; } .circle { transition-property: width, height; transition-duration: 2s; position: fixed; transform: translateX(-50%) translateY(-50%); background-color: red; border-radius: 50%; } </style></head><body> <button onclick="go()">Click me</button> <script> function go() { showCircle(150, 150, 100).then(div => { div.classList.add('message-ball'); div.append("Hello, world!"); }); } function showCircle(cx, cy, radius) { let div = document.createElement('div'); div.style.width = 0; div.style.height = 0; div.style.left = cx + 'px'; div.style.top = cy + 'px'; div.className = 'circle'; document.body.append(div); return new Promise(resolve => { setTimeout(() => { div.style.width = radius * 2 + 'px'; div.style.height = radius * 2 + 'px'; div.addEventListener('transitionend', function handler() { div.removeEventListener('transitionend', handler); resolve(div); }); }, 0); }) } </script></body></html>
点击 Click me 按钮后,会呈现一个圆形。