javascript 结合两个承诺
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31700528/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Combining two promises
提问by Marc A
I am really new to JavaScript and promises and to be honest I don't fully understand how promises work so I need some help.
我对 JavaScript 和 promises 真的很陌生,老实说我不完全理解 promises 是如何工作的,所以我需要一些帮助。
I am using Google Cloud Messaging to push notifications from my site to my users. When users receive a notification and clicks on it, it opens a URL stored in a IndexedDB.
我正在使用 Google Cloud Messaging 将通知从我的网站推送给我的用户。当用户收到通知并点击它时,它会打开一个存储在 IndexedDB 中的 URL。
importScripts('IndexDBWrapper.js');
var KEY_VALUE_STORE_NAME = 'key-value-store', idb;
function getIdb() {
if (!idb) {
idb = new IndexDBWrapper(KEY_VALUE_STORE_NAME, 1, function (db) {
db.createObjectStore(KEY_VALUE_STORE_NAME);
});
}
return idb;
}
self.addEventListener('notificationclick', function (event) {
console.log('On notification click: ', event);
event.notification.close();
event.waitUntil(getIdb().get(KEY_VALUE_STORE_NAME, event.notification.tag).then(function (url) {
var redirectUrl = '/';
if (url) redirectUrl = url;
return clients.openWindow(redirectUrl);
}));
});
So in the code above, I know that the getIdb()...then() is a promise, but is the event.waitUntil also a promise?
所以在上面的代码中,我知道 getIdb()...then() 是一个承诺,但是 event.waitUntil 也是一个承诺吗?
The problem with the above code is that it opens a instance of Chrome every time the notification is clicked and I would prefer that it would utilize an existing instance if available. The following does just that:
上面代码的问题在于,每次单击通知时它都会打开一个 Chrome 实例,我更希望它使用现有实例(如果可用)。以下就是这样做的:
self.addEventListener('notificationclick', function(event) {
console.log('On notification click: ', event.notification.tag);
event.notification.close();
event.waitUntil(
clients.matchAll({
type: "window"
})
.then(function(clientList) {
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
if (client.url == '/' && 'focus' in client)
return client.focus();
}
if (clients.openWindow) {
return clients.openWindow('/');
}
})
);
});
However, now I have two promises, getIdb and clients.matchAll and I really have no idea how to combine the two promises and the two sets of code. Any help would be greatly appreciated. Thanks!
但是,现在我有两个承诺,getIdb 和 clients.matchAll,我真的不知道如何将这两个承诺和两套代码结合起来。任何帮助将不胜感激。谢谢!
For reference, here is IndexDBWrapper.js:
作为参考,这里是 IndexDBWrapper.js:
'use strict';
function promisifyRequest(obj) {
return new Promise(function(resolve, reject) {
function onsuccess(event) {
resolve(obj.result);
unlisten();
}
function onerror(event) {
reject(obj.error);
unlisten();
}
function unlisten() {
obj.removeEventListener('complete', onsuccess);
obj.removeEventListener('success', onsuccess);
obj.removeEventListener('error', onerror);
obj.removeEventListener('abort', onerror);
}
obj.addEventListener('complete', onsuccess);
obj.addEventListener('success', onsuccess);
obj.addEventListener('error', onerror);
obj.addEventListener('abort', onerror);
});
}
function IndexDBWrapper(name, version, upgradeCallback) {
var request = indexedDB.open(name, version);
this.ready = promisifyRequest(request);
request.onupgradeneeded = function(event) {
upgradeCallback(request.result, event.oldVersion);
};
}
IndexDBWrapper.supported = 'indexedDB' in self;
var IndexDBWrapperProto = IndexDBWrapper.prototype;
IndexDBWrapperProto.transaction = function(stores, modeOrCallback, callback) {
return this.ready.then(function(db) {
var mode = 'readonly';
if (modeOrCallback.apply) {
callback = modeOrCallback;
}
else if (modeOrCallback) {
mode = modeOrCallback;
}
var tx = db.transaction(stores, mode);
var val = callback(tx, db);
var promise = promisifyRequest(tx);
var readPromise;
if (!val) {
return promise;
}
if (val[0] && 'result' in val[0]) {
readPromise = Promise.all(val.map(promisifyRequest));
}
else {
readPromise = promisifyRequest(val);
}
return promise.then(function() {
return readPromise;
});
});
};
IndexDBWrapperProto.get = function(store, key) {
return this.transaction(store, function(tx) {
return tx.objectStore(store).get(key);
});
};
IndexDBWrapperProto.put = function(store, key, value) {
return this.transaction(store, 'readwrite', function(tx) {
tx.objectStore(store).put(value, key);
});
};
IndexDBWrapperProto.delete = function(store, key) {
return this.transaction(store, 'readwrite', function(tx) {
tx.objectStore(store).delete(key);
});
};
回答by Jaromanda X
One way to deal with multiple promises is with Promise.all
处理多个承诺的一种方法是 Promise.all
Promise.all([promise0, promise1, promise2]).then(function(valArray) {
// valArray[0] is result of promise0
// valArray[1] is result of promise1
// valArray[2] is result of promise2
});
read about promise.all - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
阅读 promise.all - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
回答by Brendan Ritchie
event.waitUntil()
takes a promise - this allows the browser to keep your worker alive until you've finished what you want to do (i.e. until the promise that you gave to event.waitUntil()
has resolved).
event.waitUntil()
接受承诺 - 这允许浏览器让您的工作人员保持活动状态,直到您完成您想做的事情(即,直到您给予的承诺event.waitUntil()
已解决)。
As the other answer suggests, you can use Promise.all()
within event.waitUntil
. Promise.all()
takes an array of promises and returns a promise, so you can call then
on it. Your handling function will get an array of promise results when all of the promises you've provided to Promise.all
have resolved. Your code will then look something like this (I haven't actually tested this, but it should be close):
正如另一个答案所暗示的那样,您可以Promise.all()
在event.waitUntil
. Promise.all()
接受一组承诺并返回一个承诺,因此您可以调用then
它。当您提供的所有承诺Promise.all
都已解决时,您的处理函数将获得一系列承诺结果。然后你的代码看起来像这样(我没有实际测试过这个,但应该很接近):
self.addEventListener('notificationclick', function (event) {
event.notification.close();
event.waitUntil(Promise.all([
getIdb().get(KEY_VALUE_STORE_NAME, event.notification.tag),
clients.matchAll({ type: "window" })
]).then(function (resultArray) {
var url = resultArray[0] || "/";
var clientList = resultArray[1];
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
if (client.url == '/' && 'focus' in client)
return client.focus();
}
if (clients.openWindow) {
return clients.openWindow(url);
}
}));
});
回答by Tushar Sheth
Though I am very late to the party but,
虽然我参加聚会很晚但是,
I think you can use this very light native JS library which does things for you. https://www.npmjs.com/package/easy-promise-all
我认为你可以使用这个非常轻量级的原生 JS 库,它可以为你做一些事情。https://www.npmjs.com/package/easy-promise-all
Here is the small code sample for it.
这是它的小代码示例。
var { EasyPromiseAll } = require('easy-promise-all');
EasyPromiseAll({
resultFromPromise1: Promise.resolve('first'),
resultFromPromise2: Promise.reject('second'),
}).then((results) => {
const { resultFromPromise1, resultFromPromise2 } = results;
console.log(resultFromPromise1, resultFromPromise2);
});